home *** CD-ROM | disk | FTP | other *** search
/ Programming a Multiplayer FPS in DirectX / Programming a Multiplayer FPS in DirectX (Companion CD).iso / DirectX / dxsdk_oct2004.exe / dxsdk.exe / Samples / C++ / Common / DXUT.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2004-09-30  |  209.5 KB  |  4,942 lines

  1. //--------------------------------------------------------------------------------------
  2. // File: DXUT.cpp
  3. //
  4. // DirectX SDK Direct3D sample framework
  5. //
  6. // Copyright (c) Microsoft Corporation. All rights reserved.
  7. //--------------------------------------------------------------------------------------
  8. #include "dxstdafx.h"
  9. #define MIN_WINDOW_SIZE_X 200
  10. #define MIN_WINDOW_SIZE_Y 200
  11. #define DXUTERR_SWITCHEDTOREF     MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x1001)
  12.  
  13. //--------------------------------------------------------------------------------------
  14. // Thread safety 
  15. //--------------------------------------------------------------------------------------
  16. CRITICAL_SECTION g_cs;  
  17. bool g_bThreadSafe = true;
  18.  
  19.  
  20. //--------------------------------------------------------------------------------------
  21. // Automatically enters & leaves the CS upon object creation/deletion
  22. //--------------------------------------------------------------------------------------
  23. class DXUTLock
  24. {
  25. public:
  26.     inline DXUTLock()  { if( g_bThreadSafe ) EnterCriticalSection( &g_cs ); }
  27.     inline ~DXUTLock() { if( g_bThreadSafe ) LeaveCriticalSection( &g_cs ); }
  28. };
  29.  
  30.  
  31.  
  32. //--------------------------------------------------------------------------------------
  33. // Helper macros to build member functions that access member variables with thread safety
  34. //--------------------------------------------------------------------------------------
  35. #define SET_ACCESSOR( x, y )       inline void Set##y( x t )  { DXUTLock l; m_state.m_##y = t; };
  36. #define GET_ACCESSOR( x, y )       inline x Get##y() { DXUTLock l; return m_state.m_##y; };
  37. #define GET_SET_ACCESSOR( x, y )   SET_ACCESSOR( x, y ) GET_ACCESSOR( x, y )
  38.  
  39.  
  40. #define SETP_ACCESSOR( x, y )      inline void Set##y( x* t )  { DXUTLock l; m_state.m_##y = *t; };
  41. #define GETP_ACCESSOR( x, y )      inline x* Get##y() { DXUTLock l; return &m_state.m_##y; };
  42. #define GETP_SETP_ACCESSOR( x, y ) SETP_ACCESSOR( x, y ) GETP_ACCESSOR( x, y )
  43.  
  44.  
  45. //--------------------------------------------------------------------------------------
  46. // Stores timer callback info
  47. //--------------------------------------------------------------------------------------
  48. struct DXUT_TIMER
  49. {
  50.     LPDXUTCALLBACKTIMER pCallbackTimer;
  51.     float fTimeoutInSecs;
  52.     float fCountdown;
  53.     bool  bEnabled;
  54. };
  55.  
  56.  
  57. //--------------------------------------------------------------------------------------
  58. // Stores DXUT state and data access is done with thread safety (if g_bThreadSafe==true)
  59. //--------------------------------------------------------------------------------------
  60. class DXUTState
  61. {
  62. protected:
  63.     struct STATE
  64.     {
  65.         IDirect3D9*          m_D3D;                     // the main D3D object
  66.  
  67.         IDirect3DDevice9*    m_D3DDevice;               // the D3D rendering device
  68.         CD3DEnumeration*     m_D3DEnumeration;          // CD3DEnumeration object
  69.  
  70.         DXUTDeviceSettings*  m_CurrentDeviceSettings;   // current device settings
  71.         D3DSURFACE_DESC      m_BackBufferSurfaceDesc;   // back buffer surface description
  72.         D3DCAPS9             m_Caps;                    // D3D caps for current device
  73.  
  74.         HWND  m_HWNDFocus;                  // the main app focus window
  75.         HWND  m_HWNDDeviceFullScreen;       // the main app device window in fullscreen mode
  76.         HWND  m_HWNDDeviceWindowed;         // the main app device window in windowed mode
  77.         HMONITOR m_AdapterMonitor;          // the monitor of the adapter 
  78.         double m_Time;                      // current time in seconds
  79.         float m_ElapsedTime;                // time elapsed since last frame
  80.  
  81.         DWORD m_WinStyle;                   // window style
  82.         RECT  m_WindowClientRect;           // client rect of HWND
  83.         RECT  m_FullScreenClientRect;       // client rect of HWND when fullscreen
  84.         RECT  m_WindowBoundsRect;           // window rect of HWND
  85.         HMENU m_Menu;                       // handle to menu
  86.         double m_LastStatsUpdateTime;       // last time the stats were updated
  87.         DWORD m_LastStatsUpdateFrames;      // frames count since last time the stats were updated
  88.         float m_FPS;                        // frames per second
  89.         int   m_CurrentFrameNumber;         // the current frame number
  90.         HHOOK m_KeyboardHook;               // handle to keyboard hook
  91.         bool  m_AllowShortcutKeysWhenFullscreen; // if true, when fullscreen enable shortcut keys (Windows keys, StickyKeys shortcut, ToggleKeys shortcut, FilterKeys shortcut) 
  92.         bool  m_AllowShortcutKeysWhenWindowed;   // if true, when windowed enable shortcut keys (Windows keys, StickyKeys shortcut, ToggleKeys shortcut, FilterKeys shortcut) 
  93.         bool  m_AllowShortcutKeys;          // if true, then shortcut keys are currently disabled (Windows key, etc)
  94.         STICKYKEYS m_StartupStickyKeys;     // StickyKey settings upon startup so they can be restored later
  95.         TOGGLEKEYS m_StartupToggleKeys;     // ToggleKey settings upon startup so they can be restored later
  96.         FILTERKEYS m_StartupFilterKeys;     // FilterKey settings upon startup so they can be restored later
  97.  
  98.         bool  m_HandleDefaultHotkeys;       // if true, the sample framework will handle some default hotkeys
  99.         bool  m_ShowMsgBoxOnError;          // if true, then msgboxes are displayed upon errors
  100.         bool  m_ClipCursorWhenFullScreen;   // if true, then the sample framework will keep the cursor from going outside the window when full screen
  101.         bool  m_ShowCursorWhenFullScreen;   // if true, then the sample framework will show a cursor when full screen
  102.         bool  m_ConstantFrameTime;          // if true, then elapsed frame time will always be 0.05f seconds which is good for debugging or automated capture
  103.         float m_TimePerFrame;               // the constant time per frame in seconds, only valid if m_ConstantFrameTime==true
  104.         bool  m_WireframeMode;              // if true, then D3DRS_FILLMODE==D3DFILL_WIREFRAME else D3DRS_FILLMODE==D3DFILL_SOLID 
  105.         bool  m_AutoChangeAdapter;          // if true, then the adapter will automatically change if the window is different monitor
  106.         bool  m_WindowCreatedWithDefaultPositions; // if true, then CW_USEDEFAULT was used and the window should be moved to the right adapter
  107.         int   m_ExitCode;                   // the exit code to be returned to the command line
  108.  
  109.         bool  m_DXUTInited;                 // if true, then DXUTInit() has succeeded
  110.         bool  m_WindowCreated;              // if true, then DXUTCreateWindow() or DXUTSetWindow() has succeeded
  111.         bool  m_DeviceCreated;              // if true, then DXUTCreateDevice*() or DXUTSetDevice() has succeeded
  112.  
  113.         bool  m_DXUTInitCalled;             // if true, then DXUTInit() was called
  114.         bool  m_WindowCreateCalled;         // if true, then DXUTCreateWindow() or DXUTSetWindow() was called
  115.         bool  m_DeviceCreateCalled;         // if true, then DXUTCreateDevice*() or DXUTSetDevice() was called
  116.  
  117.         bool  m_DeviceObjectsCreated;       // if true, then DeviceCreated callback has been called (if non-NULL)
  118.         bool  m_DeviceObjectsReset;         // if true, then DeviceReset callback has been called (if non-NULL)
  119.         bool  m_InsideDeviceCallback;       // if true, then the framework is inside an app device callback
  120.         bool  m_InsideMainloop;             // if true, then the framework is inside the main loop
  121.         bool  m_Active;                     // if true, then the app is the active top level window
  122.         bool  m_TimePaused;                 // if true, then time is paused
  123.         bool  m_RenderingPaused;            // if true, then rendering is paused
  124.         int   m_PauseRenderingCount;        // pause rendering ref count
  125.         int   m_PauseTimeCount;             // pause time ref count
  126.         bool  m_DeviceLost;                 // if true, then the device is lost and needs to be reset
  127.         bool  m_Minimized;                  // if true, then the HWND is minimized
  128.         bool  m_Maximized;                  // if true, then the HWND is maximized
  129.         bool  m_IgnoreSizeChange;           // if true, the sample framework won't reset the device upon HWND size change (for internal use only)
  130.         bool  m_NotifyOnMouseMove;          // if true, include WM_MOUSEMOVE in mousecallback
  131.  
  132.         int   m_OverrideAdapterOrdinal;     // if != -1, then override to use this adapter ordinal
  133.         bool  m_OverrideWindowed;           // if true, then force to start windowed
  134.         bool  m_OverrideFullScreen;         // if true, then force to start full screen
  135.         int   m_OverrideStartX;             // if != -1, then override to this X position of the window
  136.         int   m_OverrideStartY;             // if != -1, then override to this Y position of the window
  137.         int   m_OverrideWidth;              // if != 0, then override to this width
  138.         int   m_OverrideHeight;             // if != 0, then override to this height
  139.         bool  m_OverrideForceHAL;           // if true, then force to HAL device (failing if one doesn't exist)
  140.         bool  m_OverrideForceREF;           // if true, then force to REF device (failing if one doesn't exist)
  141.         bool  m_OverrideForcePureHWVP;      // if true, then force to use pure HWVP (failing if device doesn't support it)
  142.         bool  m_OverrideForceHWVP;          // if true, then force to use HWVP (failing if device doesn't support it)
  143.         bool  m_OverrideForceSWVP;          // if true, then force to use SWVP 
  144.         bool  m_OverrideConstantFrameTime;  // if true, then force to constant frame time
  145.         float m_OverrideConstantTimePerFrame; // the constant time per frame in seconds if m_OverrideConstantFrameTime==true
  146.         int   m_OverrideQuitAfterFrame;     // if != 0, then it will force the app to quit after that frame
  147.  
  148.         LPDXUTCALLBACKISDEVICEACCEPTABLE    m_IsDeviceAcceptableFunc;   // is device acceptable callback
  149.         LPDXUTCALLBACKMODIFYDEVICESETTINGS  m_ModifyDeviceSettingsFunc; // modify device settings callback
  150.         LPDXUTCALLBACKDEVICECREATED         m_DeviceCreatedFunc;        // device created callback
  151.         LPDXUTCALLBACKDEVICERESET           m_DeviceResetFunc;          // device reset callback
  152.         LPDXUTCALLBACKDEVICELOST            m_DeviceLostFunc;           // device lost callback
  153.         LPDXUTCALLBACKDEVICEDESTROYED       m_DeviceDestroyedFunc;      // device destroyed callback
  154.         LPDXUTCALLBACKFRAMEMOVE             m_FrameMoveFunc;            // frame move callback
  155.         LPDXUTCALLBACKFRAMERENDER           m_FrameRenderFunc;          // frame render callback
  156.         LPDXUTCALLBACKKEYBOARD              m_KeyboardFunc;             // keyboard callback
  157.         LPDXUTCALLBACKMOUSE                 m_MouseFunc;                // mouse callback
  158.         LPDXUTCALLBACKMSGPROC               m_WindowMsgFunc;            // window messages callback
  159.  
  160.         CD3DSettingsDlg*             m_D3DSettingsDlg;                  // CD3DSettings object
  161.         bool                         m_ShowD3DSettingsDlg;              // if true, then show the D3DSettingsDlg
  162.         bool                         m_Keys[256];                       // array of key state
  163.         bool                         m_MouseButtons[5];                 // array of mouse states
  164.  
  165.         CGrowableArray<DXUT_TIMER>*  m_TimerList;                       // list of DXUT_TIMER structs
  166.         WCHAR                        m_StaticFrameStats[256];           // static part of frames stats 
  167.         WCHAR                        m_FrameStats[256];                 // frame stats (fps, width, etc)
  168.         WCHAR                        m_DeviceStats[256];                // device stats (description, device type, etc)
  169.         WCHAR                        m_WindowTitle[256];                // window title
  170.     };
  171.     
  172.     STATE m_state;
  173.  
  174. public:
  175.     DXUTState()  { Create(); }
  176.     ~DXUTState() { Destroy(); }
  177.  
  178.     void Create()
  179.     {
  180.         // Make sure these are created before DXUTState so they 
  181.         // destroyed last because DXUTState cleanup needs them
  182.         DXUTGetGlobalDialogResourceManager();
  183.         DXUTGetGlobalResourceCache();
  184.  
  185.         ZeroMemory( &m_state, sizeof(STATE) ); 
  186.         g_bThreadSafe = true; 
  187.         InitializeCriticalSection( &g_cs ); 
  188.         m_state.m_OverrideStartX = -1; 
  189.         m_state.m_OverrideStartY = -1; 
  190.         m_state.m_OverrideAdapterOrdinal = -1; 
  191.         m_state.m_AutoChangeAdapter = true; 
  192.         m_state.m_ShowMsgBoxOnError = true;
  193.         m_state.m_AllowShortcutKeysWhenWindowed = true;
  194.         m_state.m_Active = true;
  195.     }
  196.  
  197.     void Destroy()
  198.     {
  199.         DXUTShutdown();
  200.         DeleteCriticalSection( &g_cs ); 
  201.     }
  202.  
  203.     // Macros to define access functions for thread safe access into m_state 
  204.     GET_SET_ACCESSOR( IDirect3D9*, D3D );
  205.  
  206.     GET_SET_ACCESSOR( IDirect3DDevice9*, D3DDevice );
  207.     GET_SET_ACCESSOR( CD3DEnumeration*, D3DEnumeration );   
  208.     GET_SET_ACCESSOR( DXUTDeviceSettings*, CurrentDeviceSettings );   
  209.     GETP_SETP_ACCESSOR( D3DSURFACE_DESC, BackBufferSurfaceDesc );
  210.     GETP_SETP_ACCESSOR( D3DCAPS9, Caps );
  211.  
  212.     GET_SET_ACCESSOR( HWND, HWNDFocus );
  213.     GET_SET_ACCESSOR( HWND, HWNDDeviceFullScreen );
  214.     GET_SET_ACCESSOR( HWND, HWNDDeviceWindowed );
  215.     GET_SET_ACCESSOR( HMONITOR, AdapterMonitor );
  216.     GET_SET_ACCESSOR( double, Time );
  217.     GET_SET_ACCESSOR( float, ElapsedTime );
  218.  
  219.     GET_SET_ACCESSOR( DWORD, WinStyle );
  220.     GET_SET_ACCESSOR( const RECT &, WindowClientRect );
  221.     GET_SET_ACCESSOR( const RECT &, FullScreenClientRect );
  222.     GET_SET_ACCESSOR( const RECT &, WindowBoundsRect );   
  223.     GET_SET_ACCESSOR( HMENU, Menu );   
  224.     GET_SET_ACCESSOR( double, LastStatsUpdateTime );   
  225.     GET_SET_ACCESSOR( DWORD, LastStatsUpdateFrames );   
  226.     GET_SET_ACCESSOR( float, FPS );    
  227.     GET_SET_ACCESSOR( int, CurrentFrameNumber );
  228.     GET_SET_ACCESSOR( HHOOK, KeyboardHook );
  229.     GET_SET_ACCESSOR( bool, AllowShortcutKeysWhenFullscreen );
  230.     GET_SET_ACCESSOR( bool, AllowShortcutKeysWhenWindowed );
  231.     GET_SET_ACCESSOR( bool, AllowShortcutKeys );
  232.     GET_SET_ACCESSOR( STICKYKEYS, StartupStickyKeys );
  233.     GET_SET_ACCESSOR( TOGGLEKEYS, StartupToggleKeys );
  234.     GET_SET_ACCESSOR( FILTERKEYS, StartupFilterKeys );
  235.  
  236.     GET_SET_ACCESSOR( bool, HandleDefaultHotkeys );
  237.     GET_SET_ACCESSOR( bool, ShowMsgBoxOnError );
  238.     GET_SET_ACCESSOR( bool, ClipCursorWhenFullScreen );   
  239.     GET_SET_ACCESSOR( bool, ShowCursorWhenFullScreen );
  240.     GET_SET_ACCESSOR( bool, ConstantFrameTime );
  241.     GET_SET_ACCESSOR( float, TimePerFrame );
  242.     GET_SET_ACCESSOR( bool, WireframeMode );   
  243.     GET_SET_ACCESSOR( bool, AutoChangeAdapter );
  244.     GET_SET_ACCESSOR( bool, WindowCreatedWithDefaultPositions );
  245.     GET_SET_ACCESSOR( int, ExitCode );
  246.  
  247.     GET_SET_ACCESSOR( bool, DXUTInited );
  248.     GET_SET_ACCESSOR( bool, WindowCreated );
  249.     GET_SET_ACCESSOR( bool, DeviceCreated );
  250.     GET_SET_ACCESSOR( bool, DXUTInitCalled );
  251.     GET_SET_ACCESSOR( bool, WindowCreateCalled );
  252.     GET_SET_ACCESSOR( bool, DeviceCreateCalled );
  253.     GET_SET_ACCESSOR( bool, InsideDeviceCallback );
  254.     GET_SET_ACCESSOR( bool, InsideMainloop );
  255.     GET_SET_ACCESSOR( bool, DeviceObjectsCreated );
  256.     GET_SET_ACCESSOR( bool, DeviceObjectsReset );
  257.     GET_SET_ACCESSOR( bool, Active );
  258.     GET_SET_ACCESSOR( bool, RenderingPaused );
  259.     GET_SET_ACCESSOR( bool, TimePaused );
  260.     GET_SET_ACCESSOR( int, PauseRenderingCount );
  261.     GET_SET_ACCESSOR( int, PauseTimeCount );
  262.     GET_SET_ACCESSOR( bool, DeviceLost );
  263.     GET_SET_ACCESSOR( bool, Minimized );
  264.     GET_SET_ACCESSOR( bool, Maximized );
  265.     GET_SET_ACCESSOR( bool, IgnoreSizeChange );   
  266.     GET_SET_ACCESSOR( bool, NotifyOnMouseMove );
  267.  
  268.     GET_SET_ACCESSOR( int, OverrideAdapterOrdinal );
  269.     GET_SET_ACCESSOR( bool, OverrideWindowed );
  270.     GET_SET_ACCESSOR( bool, OverrideFullScreen );
  271.     GET_SET_ACCESSOR( int, OverrideStartX );
  272.     GET_SET_ACCESSOR( int, OverrideStartY );
  273.     GET_SET_ACCESSOR( int, OverrideWidth );
  274.     GET_SET_ACCESSOR( int, OverrideHeight );
  275.     GET_SET_ACCESSOR( bool, OverrideForceHAL );
  276.     GET_SET_ACCESSOR( bool, OverrideForceREF );
  277.     GET_SET_ACCESSOR( bool, OverrideForcePureHWVP );
  278.     GET_SET_ACCESSOR( bool, OverrideForceHWVP );
  279.     GET_SET_ACCESSOR( bool, OverrideForceSWVP );
  280.     GET_SET_ACCESSOR( bool, OverrideConstantFrameTime );
  281.     GET_SET_ACCESSOR( float, OverrideConstantTimePerFrame );
  282.     GET_SET_ACCESSOR( int, OverrideQuitAfterFrame );
  283.  
  284.     GET_SET_ACCESSOR( LPDXUTCALLBACKISDEVICEACCEPTABLE, IsDeviceAcceptableFunc );
  285.     GET_SET_ACCESSOR( LPDXUTCALLBACKMODIFYDEVICESETTINGS, ModifyDeviceSettingsFunc );
  286.     GET_SET_ACCESSOR( LPDXUTCALLBACKDEVICECREATED, DeviceCreatedFunc );
  287.     GET_SET_ACCESSOR( LPDXUTCALLBACKDEVICERESET, DeviceResetFunc );
  288.     GET_SET_ACCESSOR( LPDXUTCALLBACKDEVICELOST, DeviceLostFunc );
  289.     GET_SET_ACCESSOR( LPDXUTCALLBACKDEVICEDESTROYED, DeviceDestroyedFunc );
  290.     GET_SET_ACCESSOR( LPDXUTCALLBACKFRAMEMOVE, FrameMoveFunc );
  291.     GET_SET_ACCESSOR( LPDXUTCALLBACKFRAMERENDER, FrameRenderFunc );
  292.     GET_SET_ACCESSOR( LPDXUTCALLBACKKEYBOARD, KeyboardFunc );
  293.     GET_SET_ACCESSOR( LPDXUTCALLBACKMOUSE, MouseFunc );
  294.     GET_SET_ACCESSOR( LPDXUTCALLBACKMSGPROC, WindowMsgFunc );
  295.  
  296.     GET_SET_ACCESSOR( CD3DSettingsDlg*, D3DSettingsDlg );   
  297.     GET_SET_ACCESSOR( bool, ShowD3DSettingsDlg );   
  298.  
  299.     GET_SET_ACCESSOR( CGrowableArray<DXUT_TIMER>*, TimerList );   
  300.     GET_ACCESSOR( bool*, Keys );
  301.     GET_ACCESSOR( bool*, MouseButtons );
  302.     GET_ACCESSOR( WCHAR*, StaticFrameStats );
  303.     GET_ACCESSOR( WCHAR*, FrameStats );
  304.     GET_ACCESSOR( WCHAR*, DeviceStats );    
  305.     GET_ACCESSOR( WCHAR*, WindowTitle );
  306. };
  307.  
  308.  
  309. //--------------------------------------------------------------------------------------
  310. // Global state class
  311. //--------------------------------------------------------------------------------------
  312. DXUTState& GetDXUTState()
  313. {
  314.     // Using an accessor function gives control of the construction order
  315.     static DXUTState state;
  316.     return state;
  317. }
  318.  
  319.  
  320. //--------------------------------------------------------------------------------------
  321. // Internal functions forward declarations
  322. //--------------------------------------------------------------------------------------
  323. typedef IDirect3D9* (WINAPI* LPDIRECT3DCREATE9)(UINT SDKVersion);
  324. typedef DECLSPEC_IMPORT UINT (WINAPI* LPTIMEBEGINPERIOD)( UINT uPeriod );
  325. int     DXUTMapButtonToArrayIndex( BYTE vButton );
  326. void    DXUTParseCommandLine();
  327. CD3DEnumeration* DXUTPrepareEnumerationObject( bool bEnumerate = false );
  328. CD3DSettingsDlg* DXUTPrepareSettingsDialog();
  329. void    DXUTBuildOptimalDeviceSettings( DXUTDeviceSettings* pOptimalDeviceSettings, DXUTDeviceSettings* pDeviceSettingsIn, DXUTMatchOptions* pMatchOptions );
  330. bool    DXUTDoesDeviceComboMatchPreserveOptions( CD3DEnumDeviceSettingsCombo* pDeviceSettingsCombo, DXUTDeviceSettings* pDeviceSettingsIn, DXUTMatchOptions* pMatchOptions );
  331. float   DXUTRankDeviceCombo( CD3DEnumDeviceSettingsCombo* pDeviceSettingsCombo, DXUTDeviceSettings* pDeviceSettingsIn, D3DDISPLAYMODE* pAdapterDesktopDisplayMode );
  332. void    DXUTBuildValidDeviceSettings( DXUTDeviceSettings* pDeviceSettings, CD3DEnumDeviceSettingsCombo* pBestDeviceSettingsCombo, DXUTDeviceSettings* pDeviceSettingsIn, DXUTMatchOptions* pMatchOptions );
  333. HRESULT DXUTFindValidResolution( CD3DEnumDeviceSettingsCombo* pBestDeviceSettingsCombo, D3DDISPLAYMODE displayModeIn, D3DDISPLAYMODE* pBestDisplayMode );
  334. HRESULT DXUTFindAdapterFormat( UINT AdapterOrdinal, D3DDEVTYPE DeviceType, D3DFORMAT BackBufferFormat, BOOL Windowed, D3DFORMAT* pAdapterFormat );
  335. HRESULT DXUTChangeDevice( DXUTDeviceSettings* pNewDeviceSettings, IDirect3DDevice9* pd3dDeviceFromApp, bool bForceRecreate );
  336. void    DXUTUpdateDeviceSettingsWithOverrides( DXUTDeviceSettings* pNewDeviceSettings );
  337. HRESULT DXUTInitialize3DEnvironment();
  338. void    DXUTPrepareDevice( IDirect3DDevice9* pd3dDevice );
  339. HRESULT DXUTReset3DEnvironment();
  340. void    DXUTRender3DEnvironment();
  341. void    DXUTCleanup3DEnvironment( bool bReleaseSettings = true );
  342. void    DXUTHandlePossibleSizeChange();
  343. void    DXUTAdjustWindowStyle( HWND hWnd, bool bWindowed );
  344. void    DXUTUpdateFrameStats();
  345. void    DXUTUpdateDeviceStats( D3DDEVTYPE DeviceType, DWORD BehaviorFlags, D3DADAPTER_IDENTIFIER9* pAdapterIdentifier );
  346. void    DXUTUpdateStaticFrameStats();
  347. void    DXUTHandleTimers();
  348. bool    DXUTGetCmdParam( WCHAR*& strCmdLine, WCHAR* strFlag, int nFlagLen );
  349. void    DXUTDisplayErrorMessage( HRESULT hr );
  350. LRESULT CALLBACK DXUTStaticWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
  351. UINT    DXUTColorChannelBits( D3DFORMAT fmt );
  352. UINT    DXUTStencilBits( D3DFORMAT fmt );
  353. UINT    DXUTDepthBits( D3DFORMAT fmt );
  354. void    DXUTCheckForWindowMonitorChange();
  355. HRESULT DXUTGetAdapterOrdinalFromMonitor( HMONITOR hMonitor, UINT* pAdapterOrdinal );
  356. void    DXUTAllowShortcutKeys( bool bAllowKeys );
  357.  
  358.  
  359. //--------------------------------------------------------------------------------------
  360. // External callback setup functions
  361. //--------------------------------------------------------------------------------------
  362. void DXUTSetCallbackDeviceCreated( LPDXUTCALLBACKDEVICECREATED pCallbackDeviceCreated ) { GetDXUTState().SetDeviceCreatedFunc( pCallbackDeviceCreated ); }
  363. void DXUTSetCallbackDeviceReset( LPDXUTCALLBACKDEVICERESET pCallbackDeviceReset )       { GetDXUTState().SetDeviceResetFunc( pCallbackDeviceReset ); }
  364. void DXUTSetCallbackDeviceLost( LPDXUTCALLBACKDEVICELOST pCallbackDeviceLost )          { GetDXUTState().SetDeviceLostFunc( pCallbackDeviceLost ); }
  365. void DXUTSetCallbackDeviceDestroyed( LPDXUTCALLBACKDEVICEDESTROYED pCallbackDeviceDestroyed ) { GetDXUTState().SetDeviceDestroyedFunc( pCallbackDeviceDestroyed ); }
  366. void DXUTSetCallbackFrameMove( LPDXUTCALLBACKFRAMEMOVE pCallbackFrameMove ) { GetDXUTState().SetFrameMoveFunc( pCallbackFrameMove ); }
  367. void DXUTSetCallbackFrameRender( LPDXUTCALLBACKFRAMERENDER pCallbackFrameRender )       { GetDXUTState().SetFrameRenderFunc( pCallbackFrameRender ); }
  368. void DXUTSetCallbackKeyboard( LPDXUTCALLBACKKEYBOARD pCallbackKeyboard )                { GetDXUTState().SetKeyboardFunc( pCallbackKeyboard ); }
  369. void DXUTSetCallbackMouse( LPDXUTCALLBACKMOUSE pCallbackMouse, bool bIncludeMouseMove ) { GetDXUTState().SetMouseFunc( pCallbackMouse ); GetDXUTState().SetNotifyOnMouseMove( bIncludeMouseMove ); }
  370. void DXUTSetCallbackMsgProc( LPDXUTCALLBACKMSGPROC pCallbackMsgProc )                   { GetDXUTState().SetWindowMsgFunc( pCallbackMsgProc ); }
  371.  
  372.  
  373. //--------------------------------------------------------------------------------------
  374. // Optionally parses the command line and sets if default hotkeys are handled
  375. //
  376. //       Possible command line parameters are:
  377. //          -adapter:#              forces app to use this adapter # (fails if the adapter doesn't exist)
  378. //          -windowed               forces app to start windowed
  379. //          -fullscreen             forces app to start full screen
  380. //          -forcehal               forces app to use HAL (fails if HAL doesn't exist)
  381. //          -forceref               forces app to use REF (fails if REF doesn't exist)
  382. //          -forcepurehwvp          forces app to use pure HWVP (fails if device doesn't support it)
  383. //          -forcehwvp              forces app to use HWVP (fails if device doesn't support it)
  384. //          -forceswvp              forces app to use SWVP 
  385. //          -width:#                forces app to use # for width. for full screen, it will pick the closest possible supported mode
  386. //          -height:#               forces app to use # for height. for full screen, it will pick the closest possible supported mode
  387. //          -startx:#               forces app to use # for the x coord of the window position for windowed mode
  388. //          -starty:#               forces app to use # for the y coord of the window position for windowed mode
  389. //          -constantframetime:#    forces app to use constant frame time, where # is the time/frame in seconds
  390. //          -quitafterframe:x       forces app to quit after # frames
  391. //          -noerrormsgboxes        prevents the display of message boxes generated by the framework so the application can be run without user interaction
  392. //
  393. //      Hotkeys handled by default are:
  394. //          ESC                 app exits
  395. //          Alt-Enter           toggle between full screen & windowed
  396. //          F2                  device selection dialog
  397. //          F3                  toggle HAL/REF
  398. //          F8                  toggle wire-frame mode
  399. //          Pause               pauses time
  400. //--------------------------------------------------------------------------------------
  401. HRESULT DXUTInit( bool bParseCommandLine, bool bHandleDefaultHotkeys, bool bShowMsgBoxOnError )
  402. {
  403.     GetDXUTState().SetDXUTInitCalled( true );
  404.  
  405.     // Not always needed, but lets the app create GDI dialogs
  406.     InitCommonControls();
  407.  
  408.     // Save the current sticky/toggle/filter key settings so DXUT can restore them later
  409.     STICKYKEYS sk = {sizeof(STICKYKEYS), 0};
  410.     SystemParametersInfo(SPI_GETSTICKYKEYS, sizeof(STICKYKEYS), &sk, 0);
  411.     GetDXUTState().SetStartupStickyKeys( sk );
  412.  
  413.     TOGGLEKEYS tk = {sizeof(TOGGLEKEYS), 0};
  414.     SystemParametersInfo(SPI_GETTOGGLEKEYS, sizeof(TOGGLEKEYS), &tk, 0);
  415.     GetDXUTState().SetStartupToggleKeys( tk );
  416.  
  417.     FILTERKEYS fk = {sizeof(FILTERKEYS), 0};
  418.     SystemParametersInfo(SPI_GETFILTERKEYS, sizeof(FILTERKEYS), &fk, 0);
  419.     GetDXUTState().SetStartupFilterKeys( fk );
  420.  
  421.     // Increase the accuracy of Sleep() without needing to link to winmm.lib
  422.     WCHAR wszPath[MAX_PATH+1];
  423.     if( !::GetSystemDirectory( wszPath, MAX_PATH+1 ) )
  424.         return E_FAIL;
  425.     lstrcatW( wszPath, L"\\winmm.dll" );
  426.     HINSTANCE hInstWinMM = LoadLibrary( wszPath );
  427.     if( hInstWinMM != NULL ) 
  428.     {
  429.         LPTIMEBEGINPERIOD pTimeBeginPeriod = (LPTIMEBEGINPERIOD)GetProcAddress( hInstWinMM, "timeBeginPeriod" );
  430.         if( NULL != pTimeBeginPeriod )
  431.             pTimeBeginPeriod(1);
  432.     }
  433.     FreeLibrary(hInstWinMM);
  434.  
  435.     GetDXUTState().SetShowMsgBoxOnError( bShowMsgBoxOnError );
  436.     GetDXUTState().SetHandleDefaultHotkeys( bHandleDefaultHotkeys );
  437.  
  438.     if( bParseCommandLine )
  439.         DXUTParseCommandLine();
  440.  
  441.     // Verify D3DX version
  442.     if( !D3DXCheckVersion( D3D_SDK_VERSION, D3DX_SDK_VERSION ) )
  443.     {
  444.         DXUTDisplayErrorMessage( DXUTERR_INCORRECTVERSION );
  445.         return DXUT_ERR( L"D3DXCheckVersion", DXUTERR_INCORRECTVERSION );
  446.     }
  447.  
  448.     // Create a Direct3D object if one has not already been created
  449.     IDirect3D9* pD3D = DXUTGetD3DObject();
  450.     if( pD3D == NULL )
  451.     {
  452.         // This may fail if DirectX 9 isn't installed
  453.         // This may fail if the DirectX headers are out of sync with the installed DirectX DLLs
  454.         pD3D = DXUT_Dynamic_Direct3DCreate9( D3D_SDK_VERSION );
  455.         GetDXUTState().SetD3D( pD3D );
  456.     }
  457.  
  458.     if( pD3D == NULL )
  459.     {
  460.         // If still NULL, then something went wrong
  461.         DXUTDisplayErrorMessage( DXUTERR_NODIRECT3D );
  462.         return DXUT_ERR( L"Direct3DCreate9", DXUTERR_NODIRECT3D );
  463.     }
  464.  
  465.     // Reset the timer
  466.     DXUTGetGlobalTimer()->Reset();
  467.  
  468.     GetDXUTState().SetDXUTInited( true );
  469.  
  470.     return S_OK;
  471. }
  472.  
  473.  
  474. //--------------------------------------------------------------------------------------
  475. // Parses the command line for parameters.  See DXUTInit() for list 
  476. //--------------------------------------------------------------------------------------
  477. void DXUTParseCommandLine()
  478. {
  479.     WCHAR* strCmdLine = GetCommandLine();
  480.  
  481.     // Skip past program name (first token in command line).
  482.     if (*strCmdLine == L'"')  // Check for and handle quoted program name
  483.     {
  484.         strCmdLine++;
  485.  
  486.         // Skip over until another double-quote or a null 
  487.         while (*strCmdLine && (*strCmdLine != L'"'))
  488.             strCmdLine++;
  489.  
  490.         // Skip over double-quote
  491.         if (*strCmdLine == L'"')            
  492.             strCmdLine++;    
  493.     }
  494.     else   
  495.     {
  496.         // First token wasn't a quote
  497.         while (*strCmdLine > L' ')
  498.             strCmdLine++;
  499.     }
  500.  
  501.     for(;;)
  502.     {
  503.         // Skip past any white space preceding the next token
  504.         while (*strCmdLine && (*strCmdLine <= L' '))
  505.             strCmdLine++;
  506.         if( *strCmdLine == 0 )
  507.             break;
  508.  
  509.         WCHAR strFlag[256];
  510.         int nFlagLen = 0;
  511.  
  512.         // Skip past the flag marker
  513.         if( *strCmdLine == L'/' ||
  514.             *strCmdLine == L'-' )
  515.             strCmdLine++;
  516.  
  517.         // Compare the first N letters w/o regard to case
  518.         wcscpy( strFlag, L"adapter" ); nFlagLen = (int) wcslen(strFlag);
  519.         if( _wcsnicmp( strCmdLine, strFlag, nFlagLen ) == 0 )
  520.         {
  521.             if( DXUTGetCmdParam( strCmdLine, strFlag, nFlagLen ) )
  522.             {
  523.                 int nAdapter = _wtoi(strFlag);
  524.                 GetDXUTState().SetOverrideAdapterOrdinal( nAdapter );
  525.             }
  526.             continue;
  527.         }
  528.  
  529.         wcscpy( strFlag, L"windowed" ); nFlagLen = (int) wcslen(strFlag);
  530.         if( _wcsnicmp( strCmdLine, strFlag, nFlagLen ) == 0 )
  531.         {
  532.             GetDXUTState().SetOverrideWindowed( true );
  533.             strCmdLine += nFlagLen;
  534.             continue;
  535.         }
  536.  
  537.         wcscpy( strFlag, L"fullscreen" ); nFlagLen = (int) wcslen(strFlag);
  538.         if( _wcsnicmp( strCmdLine, strFlag, nFlagLen ) == 0 )
  539.         {
  540.             GetDXUTState().SetOverrideFullScreen( true );
  541.             strCmdLine += nFlagLen;
  542.             continue;
  543.         }
  544.  
  545.         wcscpy( strFlag, L"forcehal" ); nFlagLen = (int) wcslen(strFlag);
  546.         if( _wcsnicmp( strCmdLine, strFlag, nFlagLen ) == 0 )
  547.         {
  548.             GetDXUTState().SetOverrideForceHAL( true );
  549.             strCmdLine += nFlagLen;
  550.             continue;
  551.         }
  552.  
  553.         wcscpy( strFlag, L"forceref" ); nFlagLen = (int) wcslen(strFlag);
  554.         if( _wcsnicmp( strCmdLine, strFlag, nFlagLen ) == 0 )
  555.         {
  556.             GetDXUTState().SetOverrideForceREF( true );
  557.             strCmdLine += nFlagLen;
  558.             continue;
  559.         }
  560.  
  561.         wcscpy( strFlag, L"forcepurehwvp" ); nFlagLen = (int) wcslen(strFlag);
  562.         if( _wcsnicmp( strCmdLine, strFlag, nFlagLen ) == 0 )
  563.         {
  564.             GetDXUTState().SetOverrideForcePureHWVP( true );
  565.             strCmdLine += nFlagLen;
  566.             continue;
  567.         }
  568.  
  569.         wcscpy( strFlag, L"forcehwvp" ); nFlagLen = (int) wcslen(strFlag);
  570.         if( _wcsnicmp( strCmdLine, strFlag, nFlagLen ) == 0 )
  571.         {
  572.             GetDXUTState().SetOverrideForceHWVP( true );
  573.             strCmdLine += nFlagLen;
  574.             continue;
  575.         }
  576.  
  577.         wcscpy( strFlag, L"forceswvp" ); nFlagLen = (int) wcslen(strFlag);
  578.         if( _wcsnicmp( strCmdLine, strFlag, nFlagLen ) == 0 )
  579.         {
  580.             GetDXUTState().SetOverrideForceSWVP( true );
  581.             strCmdLine += nFlagLen;
  582.             continue;
  583.         }
  584.  
  585.         wcscpy( strFlag, L"width" ); nFlagLen = (int) wcslen(strFlag);
  586.         if( _wcsnicmp( strCmdLine, strFlag, nFlagLen ) == 0 )
  587.         {
  588.             if( DXUTGetCmdParam( strCmdLine, strFlag, nFlagLen ) )
  589.             {
  590.                 int nWidth = _wtoi(strFlag);
  591.                 GetDXUTState().SetOverrideWidth( nWidth );
  592.             }
  593.             continue;
  594.         }
  595.  
  596.         wcscpy( strFlag, L"height" ); nFlagLen = (int) wcslen(strFlag);
  597.         if( _wcsnicmp( strCmdLine, strFlag, nFlagLen ) == 0 )
  598.         {
  599.             if( DXUTGetCmdParam( strCmdLine, strFlag, nFlagLen ) )
  600.             {
  601.                 int nHeight = _wtoi(strFlag);
  602.                 GetDXUTState().SetOverrideHeight( nHeight );
  603.             }
  604.             continue;
  605.         }
  606.  
  607.         wcscpy( strFlag, L"startx" );
  608.         nFlagLen = (int) wcslen(strFlag);
  609.         if( _wcsnicmp( strCmdLine, strFlag, nFlagLen ) == 0 )
  610.         {
  611.             if( DXUTGetCmdParam( strCmdLine, strFlag, nFlagLen ) )
  612.             {
  613.                 int nX = _wtoi(strFlag);
  614.                 GetDXUTState().SetOverrideStartX( nX );
  615.             }
  616.             continue;
  617.         }
  618.  
  619.         wcscpy( strFlag, L"starty" );
  620.         nFlagLen = (int) wcslen(strFlag);
  621.         if( _wcsnicmp( strCmdLine, strFlag, nFlagLen ) == 0 )
  622.         {
  623.             if( DXUTGetCmdParam( strCmdLine, strFlag, nFlagLen ) )
  624.             {
  625.                 int nY = _wtoi(strFlag);
  626.                 GetDXUTState().SetOverrideStartY( nY );
  627.             }
  628.             continue;
  629.         }
  630.  
  631.         wcscpy( strFlag, L"constantframetime" ); nFlagLen = (int) wcslen(strFlag);
  632.         if( _wcsnicmp( strCmdLine, strFlag, nFlagLen ) == 0 )
  633.         {
  634.             float fTimePerFrame;
  635.             if( DXUTGetCmdParam( strCmdLine, strFlag, nFlagLen ) )
  636.                 fTimePerFrame = (float)wcstod( strFlag, NULL );
  637.             else
  638.                 fTimePerFrame = 0.0333f;
  639.             GetDXUTState().SetOverrideConstantFrameTime( true );
  640.             GetDXUTState().SetOverrideConstantTimePerFrame( fTimePerFrame );
  641.             DXUTSetConstantFrameTime( true, fTimePerFrame );
  642.             continue;
  643.         }
  644.  
  645.         wcscpy( strFlag, L"quitafterframe" ); nFlagLen = (int) wcslen(strFlag);
  646.         if( _wcsnicmp( strCmdLine, strFlag, nFlagLen ) == 0 )
  647.         {
  648.             if( DXUTGetCmdParam( strCmdLine, strFlag, nFlagLen ) )
  649.             {
  650.                 int nFrame = _wtoi(strFlag);
  651.                 GetDXUTState().SetOverrideQuitAfterFrame( nFrame );
  652.             }
  653.             continue;
  654.         }      
  655.         
  656.         wcscpy( strFlag, L"noerrormsgboxes" ); nFlagLen = (int) wcslen(strFlag);
  657.         if( _wcsnicmp( strCmdLine, strFlag, nFlagLen ) == 0 )
  658.         {
  659.             GetDXUTState().SetShowMsgBoxOnError( false );
  660.             strCmdLine += nFlagLen;
  661.             continue;
  662.         }        
  663.  
  664.         // Unrecognized flag
  665.         wcsncpy( strFlag, strCmdLine, 256 ); strFlag[255] = 0; 
  666.         WCHAR* strSpace = strFlag;
  667.         while (*strSpace && (*strSpace > L' '))
  668.             strSpace++;
  669.         *strSpace = 0;
  670.  
  671.         DXUTOutputDebugString( L"Unrecognized flag: %s", strFlag );
  672.         strCmdLine += wcslen(strFlag);
  673.     }
  674. }
  675.  
  676.  
  677. //--------------------------------------------------------------------------------------
  678. // Helper function for DXUTParseCommandLine.  Updates strCmdLine and strFlag 
  679. //      Example: if strCmdLine=="-width:1024 -forceref"
  680. // then after: strCmdLine==" -forceref" and strFlag=="1024"
  681. //--------------------------------------------------------------------------------------
  682. bool DXUTGetCmdParam( WCHAR*& strCmdLine, WCHAR* strFlag, int nFlagLen )
  683. {
  684.     strCmdLine += nFlagLen;
  685.     if( *strCmdLine == L':' )
  686.     {       
  687.         strCmdLine++; // Skip ':'
  688.  
  689.         // Place NULL terminator in strFlag after current token
  690.         wcsncpy( strFlag, strCmdLine, 256 );
  691.         strFlag[255] = 0;
  692.         WCHAR* strSpace = strFlag;
  693.         while (*strSpace && (*strSpace > L' '))
  694.             strSpace++;
  695.         *strSpace = 0;
  696.     
  697.         // Update strCmdLine
  698.         strCmdLine += wcslen(strFlag);
  699.         return true;
  700.     }
  701.     else
  702.     {
  703.         strFlag[0] = 0;
  704.         return false;
  705.     }
  706. }
  707.  
  708.  
  709. //--------------------------------------------------------------------------------------
  710. // Creates a window with the specified window title, icon, menu, and 
  711. // starting position.  If DXUTInit() has not already been called, it will
  712. // call it with the default parameters.  Instead of calling this, you can 
  713. // call DXUTSetWindow() to use an existing window.  
  714. //--------------------------------------------------------------------------------------
  715. HRESULT DXUTCreateWindow( const WCHAR* strWindowTitle, HINSTANCE hInstance, 
  716.                           HICON hIcon, HMENU hMenu, int x, int y )
  717. {
  718.     HRESULT hr;
  719.  
  720.     // Not allowed to call this from inside the device callbacks
  721.     if( GetDXUTState().GetInsideDeviceCallback() )
  722.         return DXUT_ERR_MSGBOX( L"DXUTCreateWindow", E_FAIL );
  723.  
  724.     GetDXUTState().SetWindowCreateCalled( true );
  725.  
  726.     if( !GetDXUTState().GetDXUTInited() ) 
  727.     {
  728.         // If DXUTInit() was already called and failed, then fail.
  729.         // DXUTInit() must first succeed for this function to succeed
  730.         if( GetDXUTState().GetDXUTInitCalled() )
  731.             return E_FAIL; 
  732.  
  733.         // If DXUTInit() hasn't been called, then automatically call it
  734.         // with default params
  735.         hr = DXUTInit();
  736.         if( FAILED(hr) )
  737.             return hr;
  738.     }
  739.  
  740.     if( DXUTGetHWNDFocus() == NULL )
  741.     {
  742.         if( hInstance == NULL ) 
  743.             hInstance = (HINSTANCE)GetModuleHandle(NULL);
  744.  
  745.         WCHAR szExePath[MAX_PATH];
  746.         GetModuleFileName( NULL, szExePath, MAX_PATH );
  747.         if( hIcon == NULL ) // If the icon is NULL, then use the first one found in the exe
  748.             hIcon = ExtractIcon( hInstance, szExePath, 0 ); 
  749.  
  750.         // Register the windows class
  751.         WNDCLASS wndClass;
  752.         wndClass.style = CS_DBLCLKS;
  753.         wndClass.lpfnWndProc = DXUTStaticWndProc;
  754.         wndClass.cbClsExtra = 0;
  755.         wndClass.cbWndExtra = 0;
  756.         wndClass.hInstance = hInstance;
  757.         wndClass.hIcon = hIcon;
  758.         wndClass.hCursor = LoadCursor( NULL, IDC_ARROW );
  759.         wndClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
  760.         wndClass.lpszMenuName = NULL;
  761.         wndClass.lpszClassName = L"Direct3DWindowClass";
  762.  
  763.         if( !RegisterClass( &wndClass ) )
  764.         {
  765.             DWORD dwError = GetLastError();
  766.             if( dwError != ERROR_CLASS_ALREADY_EXISTS )
  767.                 return DXUT_ERR_MSGBOX( L"RegisterClass", HRESULT_FROM_WIN32(dwError) );
  768.         }
  769.  
  770.         // Set the window's initial style.  It is invisible initially since it might
  771.         // be resized later
  772.         DWORD dwWindowStyle = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | 
  773.                               WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
  774.         GetDXUTState().SetWinStyle( dwWindowStyle );
  775.         
  776.         RECT rc;
  777.  
  778.         // Override the window's initial & size position if there were cmd line args
  779.         if( GetDXUTState().GetOverrideStartX() != -1 )
  780.             x = GetDXUTState().GetOverrideStartX();
  781.         if( GetDXUTState().GetOverrideStartY() != -1 )
  782.             y = GetDXUTState().GetOverrideStartY();
  783.  
  784.         GetDXUTState().SetWindowCreatedWithDefaultPositions( false );
  785.         if( x == CW_USEDEFAULT && y == CW_USEDEFAULT )
  786.             GetDXUTState().SetWindowCreatedWithDefaultPositions( true );
  787.  
  788.         // Find the window's initial size, but it might be changed later
  789.         int nDefaultWidth = 640;
  790.         int nDefaultHeight = 480;
  791.         if( GetDXUTState().GetOverrideWidth() != 0 )
  792.             nDefaultWidth = GetDXUTState().GetOverrideWidth();
  793.         if( GetDXUTState().GetOverrideHeight() != 0 )
  794.             nDefaultHeight = GetDXUTState().GetOverrideHeight();
  795.         SetRect( &rc, 0, 0, nDefaultWidth, nDefaultHeight );        
  796.         AdjustWindowRect( &rc, dwWindowStyle, ( hMenu != NULL ) ? true : false );
  797.  
  798.         WCHAR* strCachedWindowTitle = GetDXUTState().GetWindowTitle();
  799.         wcsncpy( strCachedWindowTitle, strWindowTitle, 256 );
  800.         strCachedWindowTitle[255] = 0;
  801.  
  802.         // Create the render window
  803.         HWND hWnd = CreateWindow( L"Direct3DWindowClass", strWindowTitle, dwWindowStyle,
  804.                                x, y, (rc.right-rc.left), (rc.bottom-rc.top), 0,
  805.                                hMenu, hInstance, 0 );
  806.         if( hWnd == NULL )
  807.         {
  808.             DWORD dwError = GetLastError();
  809.             return DXUT_ERR_MSGBOX( L"CreateWindow", HRESULT_FROM_WIN32(dwError) );
  810.         }
  811.  
  812.         // Record the window's client & window rect
  813.         RECT rcWindowClient;
  814.         GetClientRect( hWnd, &rcWindowClient );
  815.         GetDXUTState().SetWindowClientRect( rcWindowClient );
  816.  
  817.         RECT rcWindowBounds;
  818.         GetWindowRect( hWnd, &rcWindowBounds );
  819.         GetDXUTState().SetWindowBoundsRect( rcWindowBounds );
  820.  
  821.         GetDXUTState().SetWindowCreated( true );
  822.         GetDXUTState().SetHWNDFocus( hWnd );
  823.         GetDXUTState().SetHWNDDeviceFullScreen( hWnd );
  824.         GetDXUTState().SetHWNDDeviceWindowed( hWnd );
  825.     }
  826.  
  827.     return S_OK;
  828. }
  829.  
  830.  
  831. //--------------------------------------------------------------------------------------
  832. // Sets a previously created window for the framework to use.  If DXUTInit() 
  833. // has not already been called, it will call it with the default parameters.  
  834. // Instead of calling this, you can call DXUTCreateWindow() to create a new window.  
  835. //--------------------------------------------------------------------------------------
  836. HRESULT DXUTSetWindow( HWND hWndFocus, HWND hWndDeviceFullScreen, HWND hWndDeviceWindowed, bool bHandleMessages )
  837. {
  838.     HRESULT hr;
  839.  
  840.     // Not allowed to call this from inside the device callbacks
  841.     if( GetDXUTState().GetInsideDeviceCallback() )
  842.         return DXUT_ERR_MSGBOX( L"DXUTCreateWindow", E_FAIL );
  843.  
  844.     GetDXUTState().SetWindowCreateCalled( true );
  845.  
  846.     // To avoid confusion, we do not allow any HWND to be NULL here.  The
  847.     // caller must pass in valid HWND for all three parameters.  The same
  848.     // HWND may be used for more than one parameter.
  849.     if( hWndFocus == NULL || hWndDeviceFullScreen == NULL || hWndDeviceWindowed == NULL )
  850.         return DXUT_ERR_MSGBOX( L"DXUTSetWindow", E_INVALIDARG );
  851.  
  852.     // If subclassing the window, set the pointer to the local window procedure
  853.     if( bHandleMessages )
  854.     {
  855.         // Switch window procedures
  856. #ifdef _WIN64
  857.         LONG_PTR nResult = SetWindowLongPtr( hWndFocus, GWLP_WNDPROC, (LONG_PTR)DXUTStaticWndProc );
  858. #else
  859.         LONG_PTR nResult = SetWindowLongPtr( hWndFocus, GWLP_WNDPROC, (LONG)(LONG_PTR)DXUTStaticWndProc );
  860. #endif 
  861.  
  862.         DWORD dwError = GetLastError();
  863.         if( nResult == 0 )
  864.             return DXUT_ERR_MSGBOX( L"SetWindowLongPtr", HRESULT_FROM_WIN32(dwError) );
  865.     }
  866.  
  867.     if( !GetDXUTState().GetDXUTInited() ) 
  868.     {
  869.         // If DXUTInit() was already called and failed, then fail.
  870.         // DXUTInit() must first succeed for this function to succeed
  871.         if( GetDXUTState().GetDXUTInitCalled() )
  872.             return E_FAIL; 
  873.  
  874.         // If DXUTInit() hasn't been called, then automatically call it
  875.         // with default params
  876.         hr = DXUTInit();
  877.         if( FAILED(hr) )
  878.             return hr;
  879.     }
  880.  
  881.     WCHAR* strCachedWindowTitle = GetDXUTState().GetWindowTitle();
  882.     GetWindowText( hWndFocus, strCachedWindowTitle, 255 );
  883.     strCachedWindowTitle[255] = 0;
  884.  
  885.     // Get the window's initial style
  886.     DWORD dwWindowStyle = GetWindowLong( hWndDeviceWindowed, GWL_STYLE );
  887.     GetDXUTState().SetWinStyle( dwWindowStyle );
  888.     GetDXUTState().SetWindowCreatedWithDefaultPositions( false );
  889.  
  890.     // Store the client and window rects of the windowed-mode device window
  891.     RECT rcClient;
  892.     GetClientRect( hWndDeviceWindowed, &rcClient );
  893.     GetDXUTState().SetWindowClientRect( rcClient );
  894.  
  895.     RECT rcWindow;
  896.     GetWindowRect( hWndDeviceWindowed, &rcWindow );
  897.     GetDXUTState().SetWindowBoundsRect( rcWindow );
  898.  
  899.     GetDXUTState().SetWindowCreated( true );
  900.     GetDXUTState().SetHWNDFocus( hWndFocus );
  901.     GetDXUTState().SetHWNDDeviceFullScreen( hWndDeviceFullScreen );
  902.     GetDXUTState().SetHWNDDeviceWindowed( hWndDeviceWindowed );
  903.  
  904.     return S_OK;
  905. }
  906.  
  907.  
  908. //--------------------------------------------------------------------------------------
  909. // Creates a Direct3D device. If DXUTCreateWindow() or DXUTSetWindow() has not already 
  910. // been called, it will call DXUTCreateWindow() with the default parameters.  
  911. // Instead of calling this, you can call DXUTSetDevice() or DXUTCreateDeviceFromSettings() 
  912. //--------------------------------------------------------------------------------------
  913. HRESULT DXUTCreateDevice( UINT AdapterOrdinal, bool bWindowed, 
  914.                           int nSuggestedWidth, int nSuggestedHeight,
  915.                           LPDXUTCALLBACKISDEVICEACCEPTABLE pCallbackIsDeviceAcceptable,
  916.                           LPDXUTCALLBACKMODIFYDEVICESETTINGS pCallbackModifyDeviceSettings )
  917. {
  918.     HRESULT hr;
  919.  
  920.     // Not allowed to call this from inside the device callbacks
  921.     if( GetDXUTState().GetInsideDeviceCallback() )
  922.         return DXUT_ERR_MSGBOX( L"DXUTCreateWindow", E_FAIL );
  923.  
  924.     // Record the function arguments in the global state 
  925.     GetDXUTState().SetIsDeviceAcceptableFunc( pCallbackIsDeviceAcceptable );
  926.     GetDXUTState().SetModifyDeviceSettingsFunc( pCallbackModifyDeviceSettings );
  927.  
  928.     GetDXUTState().SetDeviceCreateCalled( true );
  929.  
  930.     // If DXUTCreateWindow() or DXUTSetWindow() has not already been called, 
  931.     // then call DXUTCreateWindow() with the default parameters.         
  932.     if( !GetDXUTState().GetWindowCreated() ) 
  933.     {
  934.         // If DXUTCreateWindow() or DXUTSetWindow() was already called and failed, then fail.
  935.         // DXUTCreateWindow() or DXUTSetWindow() must first succeed for this function to succeed
  936.         if( GetDXUTState().GetWindowCreateCalled() )
  937.             return E_FAIL; 
  938.  
  939.         // If DXUTCreateWindow() or DXUTSetWindow() hasn't been called, then 
  940.         // automatically call DXUTCreateWindow() with default params
  941.         hr = DXUTCreateWindow();
  942.         if( FAILED(hr) )
  943.             return hr;
  944.     }
  945.  
  946.     // Force an enumeration with the new IsDeviceAcceptable callback
  947.     DXUTPrepareEnumerationObject( true );
  948.  
  949.     DXUTMatchOptions matchOptions;
  950.     matchOptions.eAdapterOrdinal     = DXUTMT_PRESERVE_INPUT;
  951.     matchOptions.eDeviceType         = DXUTMT_IGNORE_INPUT;
  952.     matchOptions.eWindowed           = DXUTMT_PRESERVE_INPUT;
  953.     matchOptions.eAdapterFormat      = DXUTMT_IGNORE_INPUT;
  954.     matchOptions.eVertexProcessing   = DXUTMT_IGNORE_INPUT;
  955.     matchOptions.eResolution         = DXUTMT_CLOSEST_TO_INPUT;
  956.     matchOptions.eBackBufferFormat   = DXUTMT_IGNORE_INPUT;
  957.     matchOptions.eBackBufferCount    = DXUTMT_IGNORE_INPUT;
  958.     matchOptions.eMultiSample        = DXUTMT_IGNORE_INPUT;
  959.     matchOptions.eSwapEffect         = DXUTMT_IGNORE_INPUT;
  960.     matchOptions.eDepthFormat        = DXUTMT_IGNORE_INPUT;
  961.     matchOptions.eStencilFormat      = DXUTMT_IGNORE_INPUT;
  962.     matchOptions.ePresentFlags       = DXUTMT_IGNORE_INPUT;
  963.     matchOptions.eRefreshRate        = DXUTMT_IGNORE_INPUT;
  964.     matchOptions.ePresentInterval    = DXUTMT_IGNORE_INPUT;
  965.  
  966.     DXUTDeviceSettings deviceSettings;
  967.     ZeroMemory( &deviceSettings, sizeof(DXUTDeviceSettings) );
  968.     deviceSettings.AdapterOrdinal      = AdapterOrdinal;
  969.     deviceSettings.pp.Windowed         = bWindowed;
  970.     deviceSettings.pp.BackBufferWidth  = nSuggestedWidth;
  971.     deviceSettings.pp.BackBufferHeight = nSuggestedHeight;
  972.  
  973.     // Override with settings from the command line
  974.     if( GetDXUTState().GetOverrideWidth() != 0 )
  975.         deviceSettings.pp.BackBufferWidth = GetDXUTState().GetOverrideWidth();
  976.     if( GetDXUTState().GetOverrideHeight() != 0 )
  977.         deviceSettings.pp.BackBufferHeight = GetDXUTState().GetOverrideHeight();
  978.  
  979.     if( GetDXUTState().GetOverrideAdapterOrdinal() != -1 )
  980.         deviceSettings.AdapterOrdinal = GetDXUTState().GetOverrideAdapterOrdinal();
  981.  
  982.     if( GetDXUTState().GetOverrideFullScreen() )
  983.     {
  984.         deviceSettings.pp.Windowed = FALSE;
  985.         if( GetDXUTState().GetOverrideWidth() == 0 && GetDXUTState().GetOverrideHeight() == 0 )
  986.             matchOptions.eResolution = DXUTMT_IGNORE_INPUT;
  987.     }
  988.     if( GetDXUTState().GetOverrideWindowed() )
  989.         deviceSettings.pp.Windowed = TRUE;
  990.  
  991.     if( GetDXUTState().GetOverrideForceHAL() )
  992.     {
  993.         deviceSettings.DeviceType = D3DDEVTYPE_HAL;
  994.         matchOptions.eDeviceType = DXUTMT_PRESERVE_INPUT;
  995.     }
  996.     if( GetDXUTState().GetOverrideForceREF() )
  997.     {
  998.         deviceSettings.DeviceType = D3DDEVTYPE_REF;
  999.         matchOptions.eDeviceType = DXUTMT_PRESERVE_INPUT;
  1000.     }
  1001.  
  1002.     if( GetDXUTState().GetOverrideForcePureHWVP() )
  1003.     {
  1004.         deviceSettings.BehaviorFlags = D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE;
  1005.         matchOptions.eVertexProcessing = DXUTMT_PRESERVE_INPUT;
  1006.     }
  1007.     else if( GetDXUTState().GetOverrideForceHWVP() )
  1008.     {
  1009.         deviceSettings.BehaviorFlags = D3DCREATE_HARDWARE_VERTEXPROCESSING;
  1010.         matchOptions.eVertexProcessing = DXUTMT_PRESERVE_INPUT;
  1011.     }
  1012.     else if( GetDXUTState().GetOverrideForceSWVP() )
  1013.     {
  1014.         deviceSettings.BehaviorFlags = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
  1015.         matchOptions.eVertexProcessing = DXUTMT_PRESERVE_INPUT;
  1016.     }
  1017.  
  1018.     hr = DXUTFindValidDeviceSettings( &deviceSettings, &deviceSettings, &matchOptions );
  1019.     if( FAILED(hr) ) // the call will fail if no valid devices were found
  1020.     {
  1021.         DXUTDisplayErrorMessage( hr );
  1022.         return DXUT_ERR( L"DXUTFindValidDeviceSettings", hr );
  1023.     }
  1024.  
  1025.     // If the ModifyDeviceSettings callback is non-NULL, then call it to 
  1026.     // let the app change the settings
  1027.     if( pCallbackModifyDeviceSettings )
  1028.     {
  1029.         D3DCAPS9 caps;
  1030.         IDirect3D9* pD3D = DXUTGetD3DObject();
  1031.         pD3D->GetDeviceCaps( deviceSettings.AdapterOrdinal, deviceSettings.DeviceType, &caps );
  1032.  
  1033.         pCallbackModifyDeviceSettings( &deviceSettings, &caps );
  1034.     }
  1035.  
  1036.     // Change to a Direct3D device created from the new device settings.  
  1037.     // If there is an existing device, then either reset or recreated the scene
  1038.     hr = DXUTChangeDevice( &deviceSettings, NULL, false );
  1039.     if( FAILED(hr) )
  1040.         return hr;
  1041.  
  1042.     return S_OK;
  1043. }
  1044.  
  1045.  
  1046. //--------------------------------------------------------------------------------------
  1047. // Passes a previously created Direct3D device for use by the framework.  
  1048. // If DXUTCreateWindow() has not already been called, it will call it with the 
  1049. // default parameters.  Instead of calling this, you can call DXUTCreateDevice() or 
  1050. // DXUTCreateDeviceFromSettings() 
  1051. //--------------------------------------------------------------------------------------
  1052. HRESULT DXUTSetDevice( IDirect3DDevice9* pd3dDevice )
  1053. {
  1054.     HRESULT hr;
  1055.  
  1056.     if( pd3dDevice == NULL )
  1057.         return DXUT_ERR_MSGBOX( L"DXUTSetDevice", E_INVALIDARG );
  1058.  
  1059.     // Not allowed to call this from inside the device callbacks
  1060.     if( GetDXUTState().GetInsideDeviceCallback() )
  1061.         return DXUT_ERR_MSGBOX( L"DXUTCreateWindow", E_FAIL );
  1062.  
  1063.     GetDXUTState().SetDeviceCreateCalled( true );
  1064.  
  1065.     // If DXUTCreateWindow() or DXUTSetWindow() has not already been called, 
  1066.     // then call DXUTCreateWindow() with the default parameters.         
  1067.     if( !GetDXUTState().GetWindowCreated() ) 
  1068.     {
  1069.         // If DXUTCreateWindow() or DXUTSetWindow() was already called and failed, then fail.
  1070.         // DXUTCreateWindow() or DXUTSetWindow() must first succeed for this function to succeed
  1071.         if( GetDXUTState().GetWindowCreateCalled() )
  1072.             return E_FAIL; 
  1073.  
  1074.         // If DXUTCreateWindow() or DXUTSetWindow() hasn't been called, then 
  1075.         // automatically call DXUTCreateWindow() with default params
  1076.         hr = DXUTCreateWindow();
  1077.         if( FAILED(hr) )
  1078.             return hr;
  1079.     }
  1080.  
  1081.     DXUTDeviceSettings* pDeviceSettings = new DXUTDeviceSettings;
  1082.     if( pDeviceSettings == NULL )
  1083.         return E_OUTOFMEMORY;
  1084.     ZeroMemory( pDeviceSettings, sizeof(DXUTDeviceSettings) );
  1085.  
  1086.     // Get the present params from the swap chain
  1087.     IDirect3DSurface9* pBackBuffer = NULL;
  1088.     hr = pd3dDevice->GetBackBuffer( 0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer );
  1089.     if( SUCCEEDED(hr) )
  1090.     {
  1091.         IDirect3DSwapChain9* pSwapChain = NULL;
  1092.         hr = pBackBuffer->GetContainer( IID_IDirect3DSwapChain9, (void**) &pSwapChain );
  1093.         if( SUCCEEDED(hr) )
  1094.         {
  1095.             pSwapChain->GetPresentParameters( &pDeviceSettings->pp );
  1096.             SAFE_RELEASE( pSwapChain );
  1097.         }
  1098.  
  1099.         SAFE_RELEASE( pBackBuffer );
  1100.     }
  1101.  
  1102.     D3DDEVICE_CREATION_PARAMETERS d3dCreationParams;
  1103.     pd3dDevice->GetCreationParameters( &d3dCreationParams );
  1104.  
  1105.     // Fill out the rest of the device settings struct
  1106.     pDeviceSettings->AdapterOrdinal = d3dCreationParams.AdapterOrdinal;
  1107.     pDeviceSettings->DeviceType     = d3dCreationParams.DeviceType;
  1108.     DXUTFindAdapterFormat( pDeviceSettings->AdapterOrdinal, pDeviceSettings->DeviceType, 
  1109.                            pDeviceSettings->pp.BackBufferFormat, pDeviceSettings->pp.Windowed, 
  1110.                            &pDeviceSettings->AdapterFormat );
  1111.     pDeviceSettings->BehaviorFlags  = d3dCreationParams.BehaviorFlags;
  1112.  
  1113.     // Change to the Direct3D device passed in
  1114.     hr = DXUTChangeDevice( pDeviceSettings, pd3dDevice, false );
  1115.     if( FAILED(hr) ) 
  1116.         return hr;
  1117.  
  1118.     return S_OK;
  1119. }
  1120.  
  1121.  
  1122. //--------------------------------------------------------------------------------------
  1123. // Tells the framework to change to a device created from the passed in device settings
  1124. // If DXUTCreateWindow() has not already been called, it will call it with the 
  1125. // default parameters.  Instead of calling this, you can call DXUTCreateDevice() 
  1126. // or DXUTSetDevice() 
  1127. //--------------------------------------------------------------------------------------
  1128. HRESULT DXUTCreateDeviceFromSettings( DXUTDeviceSettings* pDeviceSettings, bool bPreserveInput )
  1129. {
  1130.     HRESULT hr;
  1131.  
  1132.     GetDXUTState().SetDeviceCreateCalled( true );
  1133.  
  1134.     // If DXUTCreateWindow() or DXUTSetWindow() has not already been called, 
  1135.     // then call DXUTCreateWindow() with the default parameters.         
  1136.     if( !GetDXUTState().GetWindowCreated() ) 
  1137.     {
  1138.         // If DXUTCreateWindow() or DXUTSetWindow() was already called and failed, then fail.
  1139.         // DXUTCreateWindow() or DXUTSetWindow() must first succeed for this function to succeed
  1140.         if( GetDXUTState().GetWindowCreateCalled() )
  1141.             return E_FAIL; 
  1142.  
  1143.         // If DXUTCreateWindow() or DXUTSetWindow() hasn't been called, then 
  1144.         // automatically call DXUTCreateWindow() with default params
  1145.         hr = DXUTCreateWindow();
  1146.         if( FAILED(hr) )
  1147.             return hr;
  1148.     }
  1149.  
  1150.     if( !bPreserveInput )
  1151.     {
  1152.         // If not preserving the input, then find the closest valid to it
  1153.         DXUTMatchOptions matchOptions;
  1154.         matchOptions.eAdapterOrdinal     = DXUTMT_CLOSEST_TO_INPUT;
  1155.         matchOptions.eDeviceType         = DXUTMT_CLOSEST_TO_INPUT;
  1156.         matchOptions.eWindowed           = DXUTMT_CLOSEST_TO_INPUT;
  1157.         matchOptions.eAdapterFormat      = DXUTMT_CLOSEST_TO_INPUT;
  1158.         matchOptions.eVertexProcessing   = DXUTMT_CLOSEST_TO_INPUT;
  1159.         matchOptions.eResolution         = DXUTMT_CLOSEST_TO_INPUT;
  1160.         matchOptions.eBackBufferFormat   = DXUTMT_CLOSEST_TO_INPUT;
  1161.         matchOptions.eBackBufferCount    = DXUTMT_CLOSEST_TO_INPUT;
  1162.         matchOptions.eMultiSample        = DXUTMT_CLOSEST_TO_INPUT;
  1163.         matchOptions.eSwapEffect         = DXUTMT_CLOSEST_TO_INPUT;
  1164.         matchOptions.eDepthFormat        = DXUTMT_CLOSEST_TO_INPUT;
  1165.         matchOptions.eStencilFormat      = DXUTMT_CLOSEST_TO_INPUT;
  1166.         matchOptions.ePresentFlags       = DXUTMT_CLOSEST_TO_INPUT;
  1167.         matchOptions.eRefreshRate        = DXUTMT_CLOSEST_TO_INPUT;
  1168.         matchOptions.ePresentInterval    = DXUTMT_CLOSEST_TO_INPUT;
  1169.  
  1170.         hr = DXUTFindValidDeviceSettings( pDeviceSettings, pDeviceSettings, &matchOptions );
  1171.         if( FAILED(hr) ) // the call will fail if no valid devices were found
  1172.         {
  1173.             DXUTDisplayErrorMessage( hr );
  1174.             return DXUT_ERR( L"DXUTFindValidDeviceSettings", hr );
  1175.         }
  1176.     }
  1177.  
  1178.     // Change to a Direct3D device created from the new device settings.  
  1179.     // If there is an existing device, then either reset or recreate the scene
  1180.     hr = DXUTChangeDevice( pDeviceSettings, NULL, false );
  1181.     if( FAILED(hr) )
  1182.         return hr;
  1183.  
  1184.     return S_OK;
  1185. }
  1186.  
  1187.  
  1188. //--------------------------------------------------------------------------------------
  1189. // Toggle between full screen and windowed
  1190. //--------------------------------------------------------------------------------------
  1191. HRESULT DXUTToggleFullScreen()
  1192. {
  1193.     HRESULT hr;
  1194.  
  1195.     DXUTPause( true, true );
  1196.  
  1197.     // Get the current device settings and flip the windowed state then
  1198.     // find the closest valid device settings with this change
  1199.     DXUTDeviceSettings deviceSettings = DXUTGetDeviceSettings();
  1200.     deviceSettings.pp.Windowed = !deviceSettings.pp.Windowed;
  1201.  
  1202.     DXUTMatchOptions matchOptions;
  1203.     matchOptions.eAdapterOrdinal     = DXUTMT_PRESERVE_INPUT;
  1204.     matchOptions.eDeviceType         = DXUTMT_CLOSEST_TO_INPUT;
  1205.     matchOptions.eWindowed           = DXUTMT_PRESERVE_INPUT;
  1206.     matchOptions.eAdapterFormat      = DXUTMT_IGNORE_INPUT;
  1207.     matchOptions.eVertexProcessing   = DXUTMT_CLOSEST_TO_INPUT;
  1208.     matchOptions.eBackBufferFormat   = DXUTMT_IGNORE_INPUT;
  1209.     matchOptions.eBackBufferCount    = DXUTMT_CLOSEST_TO_INPUT;
  1210.     matchOptions.eMultiSample        = DXUTMT_CLOSEST_TO_INPUT;
  1211.     matchOptions.eSwapEffect         = DXUTMT_CLOSEST_TO_INPUT;
  1212.     matchOptions.eDepthFormat        = DXUTMT_CLOSEST_TO_INPUT;
  1213.     matchOptions.eStencilFormat      = DXUTMT_CLOSEST_TO_INPUT;
  1214.     matchOptions.ePresentFlags       = DXUTMT_CLOSEST_TO_INPUT;
  1215.     matchOptions.eRefreshRate        = DXUTMT_IGNORE_INPUT;
  1216.     matchOptions.ePresentInterval    = DXUTMT_IGNORE_INPUT;
  1217.  
  1218.     RECT rcWindowClient;
  1219.     if( deviceSettings.pp.Windowed )
  1220.         rcWindowClient = GetDXUTState().GetWindowClientRect();   
  1221.     else
  1222.         rcWindowClient = GetDXUTState().GetFullScreenClientRect();   
  1223.  
  1224.     int nWidth = rcWindowClient.right - rcWindowClient.left;
  1225.     int nHeight = rcWindowClient.bottom - rcWindowClient.top;
  1226.     if( nWidth > 0 && nHeight > 0 )
  1227.     {
  1228.         matchOptions.eResolution = DXUTMT_CLOSEST_TO_INPUT;
  1229.         deviceSettings.pp.BackBufferWidth = nWidth;
  1230.         deviceSettings.pp.BackBufferHeight = nHeight;
  1231.     }
  1232.     else
  1233.     {
  1234.         matchOptions.eResolution = DXUTMT_IGNORE_INPUT;
  1235.     }
  1236.     
  1237.     hr = DXUTFindValidDeviceSettings( &deviceSettings, &deviceSettings, &matchOptions );
  1238.     if( SUCCEEDED(hr) ) 
  1239.     {
  1240.         // Create a Direct3D device using the new device settings.  
  1241.         // If there is an existing device, then it will either reset or recreate the scene.
  1242.         hr = DXUTChangeDevice( &deviceSettings, NULL, false );
  1243.         if( FAILED(hr) )
  1244.         {
  1245.             // Failed creating device, try to switch back.
  1246.             deviceSettings.pp.Windowed = !deviceSettings.pp.Windowed;
  1247.             if( deviceSettings.pp.Windowed )
  1248.                 rcWindowClient = GetDXUTState().GetWindowClientRect();   
  1249.             else
  1250.                 rcWindowClient = GetDXUTState().GetFullScreenClientRect();   
  1251.  
  1252.             nWidth = rcWindowClient.right - rcWindowClient.left;
  1253.             nHeight = rcWindowClient.bottom - rcWindowClient.top;
  1254.             if( nWidth > 0 && nHeight > 0 )
  1255.             {
  1256.                 matchOptions.eResolution = DXUTMT_CLOSEST_TO_INPUT;
  1257.                 deviceSettings.pp.BackBufferWidth = nWidth;
  1258.                 deviceSettings.pp.BackBufferHeight = nHeight;
  1259.             }
  1260.             else
  1261.             {
  1262.                 matchOptions.eResolution = DXUTMT_IGNORE_INPUT;
  1263.             }
  1264.             
  1265.             DXUTFindValidDeviceSettings( &deviceSettings, &deviceSettings, &matchOptions );
  1266.  
  1267.             HRESULT hr2 = DXUTChangeDevice( &deviceSettings, NULL, false );
  1268.             if( FAILED(hr2) )
  1269.             {
  1270.                 // If this failed, then shutdown
  1271.                 DXUTShutdown();
  1272.             }
  1273.         }
  1274.     }
  1275.  
  1276.     DXUTPause( false, false );
  1277.  
  1278.     return hr;
  1279. }
  1280.  
  1281.  
  1282. //--------------------------------------------------------------------------------------
  1283. // Toggle between HAL and REF
  1284. //--------------------------------------------------------------------------------------
  1285. HRESULT DXUTToggleREF()
  1286. {
  1287.     HRESULT hr;
  1288.  
  1289.     DXUTDeviceSettings deviceSettings = DXUTGetDeviceSettings();
  1290.     if( deviceSettings.DeviceType == D3DDEVTYPE_HAL )
  1291.         deviceSettings.DeviceType = D3DDEVTYPE_REF;
  1292.     else if( deviceSettings.DeviceType == D3DDEVTYPE_REF )
  1293.         deviceSettings.DeviceType = D3DDEVTYPE_HAL;
  1294.  
  1295.     DXUTMatchOptions matchOptions;
  1296.     matchOptions.eAdapterOrdinal     = DXUTMT_PRESERVE_INPUT;
  1297.     matchOptions.eDeviceType         = DXUTMT_PRESERVE_INPUT;
  1298.     matchOptions.eWindowed           = DXUTMT_CLOSEST_TO_INPUT;
  1299.     matchOptions.eAdapterFormat      = DXUTMT_CLOSEST_TO_INPUT;
  1300.     matchOptions.eVertexProcessing   = DXUTMT_CLOSEST_TO_INPUT;
  1301.     matchOptions.eResolution         = DXUTMT_CLOSEST_TO_INPUT;
  1302.     matchOptions.eBackBufferFormat   = DXUTMT_CLOSEST_TO_INPUT;
  1303.     matchOptions.eBackBufferCount    = DXUTMT_CLOSEST_TO_INPUT;
  1304.     matchOptions.eMultiSample        = DXUTMT_CLOSEST_TO_INPUT;
  1305.     matchOptions.eSwapEffect         = DXUTMT_CLOSEST_TO_INPUT;
  1306.     matchOptions.eDepthFormat        = DXUTMT_CLOSEST_TO_INPUT;
  1307.     matchOptions.eStencilFormat      = DXUTMT_CLOSEST_TO_INPUT;
  1308.     matchOptions.ePresentFlags       = DXUTMT_CLOSEST_TO_INPUT;
  1309.     matchOptions.eRefreshRate        = DXUTMT_CLOSEST_TO_INPUT;
  1310.     matchOptions.ePresentInterval    = DXUTMT_CLOSEST_TO_INPUT;
  1311.     
  1312.     hr = DXUTFindValidDeviceSettings( &deviceSettings, &deviceSettings, &matchOptions );
  1313.     if( SUCCEEDED(hr) ) 
  1314.     {
  1315.         // Create a Direct3D device using the new device settings.  
  1316.         // If there is an existing device, then it will either reset or recreate the scene.
  1317.         hr = DXUTChangeDevice( &deviceSettings, NULL, false );
  1318.         if( FAILED( hr ) )
  1319.         {
  1320.             // Failed creating device, try to switch back.
  1321.             if( deviceSettings.DeviceType == D3DDEVTYPE_HAL )
  1322.                 deviceSettings.DeviceType = D3DDEVTYPE_REF;
  1323.             else if( deviceSettings.DeviceType == D3DDEVTYPE_REF )
  1324.                 deviceSettings.DeviceType = D3DDEVTYPE_HAL;
  1325.  
  1326.             DXUTFindValidDeviceSettings( &deviceSettings, &deviceSettings, &matchOptions );
  1327.  
  1328.             HRESULT hr2 = DXUTChangeDevice( &deviceSettings, NULL, false );
  1329.             if( FAILED(hr2) )
  1330.             {
  1331.                 // If this failed, then shutdown
  1332.                 DXUTShutdown();
  1333.             }
  1334.         }
  1335.     }
  1336.  
  1337.     return hr;
  1338. }
  1339.  
  1340.  
  1341. //--------------------------------------------------------------------------------------
  1342. // Internal helper function to prepare the enumeration object by creating it if it 
  1343. // didn't already exist and enumerating if desired.
  1344. //--------------------------------------------------------------------------------------
  1345. CD3DEnumeration* DXUTPrepareEnumerationObject( bool bEnumerate )
  1346. {
  1347.     // Create a new CD3DEnumeration object and enumerate all devices unless its already been done
  1348.     CD3DEnumeration* pd3dEnum = GetDXUTState().GetD3DEnumeration();
  1349.     if( pd3dEnum == NULL )
  1350.     {
  1351.         pd3dEnum = DXUTGetEnumeration(); 
  1352.         GetDXUTState().SetD3DEnumeration( pd3dEnum );
  1353.  
  1354.         bEnumerate = true;
  1355.     }
  1356.  
  1357.     if( bEnumerate )
  1358.     {
  1359.         // Enumerate for each adapter all of the supported display modes, 
  1360.         // device types, adapter formats, back buffer formats, window/full screen support, 
  1361.         // depth stencil formats, multisampling types/qualities, and presentations intervals.
  1362.         //
  1363.         // For each combination of device type (HAL/REF), adapter format, back buffer format, and
  1364.         // IsWindowed it will call the app's ConfirmDevice callback.  This allows the app
  1365.         // to reject or allow that combination based on its caps/etc.  It also allows the 
  1366.         // app to change the BehaviorFlags.  The BehaviorFlags defaults non-pure HWVP 
  1367.         // if supported otherwise it will default to SWVP, however the app can change this 
  1368.         // through the ConfirmDevice callback.
  1369.         IDirect3D9* pD3D = DXUTGetD3DObject();
  1370.         pd3dEnum->Enumerate( pD3D, GetDXUTState().GetIsDeviceAcceptableFunc() );
  1371.     }
  1372.     
  1373.     return pd3dEnum;
  1374. }
  1375.  
  1376.  
  1377. //--------------------------------------------------------------------------------------
  1378. // Internal helper function to prepare the settings dialog by creating it if it didn't 
  1379. // already exist and enumerating if desired.
  1380. //--------------------------------------------------------------------------------------
  1381. CD3DSettingsDlg* DXUTPrepareSettingsDialog()
  1382. {
  1383.     CD3DSettingsDlg* pD3DSettingsDlg = GetDXUTState().GetD3DSettingsDlg();
  1384.  
  1385.     if( pD3DSettingsDlg == NULL )
  1386.     {
  1387.         HRESULT hr = S_OK;
  1388.  
  1389.         pD3DSettingsDlg = DXUTGetSettingsDialog();
  1390.         GetDXUTState().SetD3DSettingsDlg( pD3DSettingsDlg );
  1391.  
  1392.         if( GetDXUTState().GetDeviceObjectsCreated() )
  1393.         {
  1394.             IDirect3DDevice9* pd3dDevice = DXUTGetD3DDevice();
  1395.             hr = pD3DSettingsDlg->OnCreateDevice( pd3dDevice );
  1396.             if( FAILED(hr) ) 
  1397.             {
  1398.                 DXUT_ERR( L"DXUTPrepareSettingsDialog", hr );
  1399.                 return pD3DSettingsDlg;
  1400.             }
  1401.         }
  1402.         
  1403.         if( GetDXUTState().GetDeviceObjectsReset() )
  1404.         {
  1405.             hr = pD3DSettingsDlg->OnResetDevice();
  1406.             if( FAILED(hr) ) 
  1407.             {
  1408.                 DXUT_ERR( L"DXUTPrepareSettingsDialog", hr );
  1409.                 return pD3DSettingsDlg;
  1410.             }
  1411.         }
  1412.     }
  1413.  
  1414.     return pD3DSettingsDlg;
  1415. }
  1416.  
  1417.  
  1418. //--------------------------------------------------------------------------------------
  1419. // This function tries to find valid device settings based upon the input device settings 
  1420. // struct and the match options.  For each device setting a match option in the 
  1421. // DXUTMatchOptions struct specifies how the function makes decisions.  For example, if 
  1422. // the caller wants a HAL device with a back buffer format of D3DFMT_A2B10G10R10 but the 
  1423. // HAL device on the system does not support D3DFMT_A2B10G10R10 however a REF device is 
  1424. // installed that does, then the function has a choice to either use REF or to change to 
  1425. // a back buffer format to compatible with the HAL device.  The match options lets the 
  1426. // caller control how these choices are made.
  1427. //
  1428. // Each match option must be one of the following types: 
  1429. //      DXUTMT_IGNORE_INPUT: Uses the closest valid value to a default 
  1430. //      DXUTMT_PRESERVE_INPUT: Uses the input without change, but may cause no valid device to be found
  1431. //      DXUTMT_CLOSEST_TO_INPUT: Uses the closest valid value to the input 
  1432. //
  1433. // If pMatchOptions is NULL then, all of the match options are assumed to be DXUTMT_IGNORE_INPUT.  
  1434. // The function returns failure if no valid device settings can be found otherwise 
  1435. // the function returns success and the valid device settings are written to pOut.
  1436. //--------------------------------------------------------------------------------------
  1437. HRESULT DXUTFindValidDeviceSettings( DXUTDeviceSettings* pOut, DXUTDeviceSettings* pIn, 
  1438.                                      DXUTMatchOptions* pMatchOptions )
  1439. {
  1440.     if( pOut == NULL )
  1441.         return DXUT_ERR_MSGBOX( L"DXUTFindValidDeviceSettings", E_INVALIDARG );
  1442.  
  1443.     CD3DEnumeration* pd3dEnum = DXUTPrepareEnumerationObject( false );
  1444.     IDirect3D9*      pD3D     = DXUTGetD3DObject();
  1445.  
  1446.     // Default to DXUTMT_IGNORE_INPUT for everything unless pMatchOptions isn't NULL
  1447.     DXUTMatchOptions defaultMatchOptions;
  1448.     if( NULL == pMatchOptions )
  1449.     {
  1450.         ZeroMemory( &defaultMatchOptions, sizeof(DXUTMatchOptions) );
  1451.         pMatchOptions = &defaultMatchOptions;
  1452.     }
  1453.  
  1454.     // Build an optimal device settings structure based upon the match 
  1455.     // options.  If the match option is set to ignore, then a optimal default value is used.
  1456.     // The default value may not exist on the system, but later this will be taken 
  1457.     // into account.
  1458.     DXUTDeviceSettings optimalDeviceSettings;
  1459.     DXUTBuildOptimalDeviceSettings( &optimalDeviceSettings, pIn, pMatchOptions );
  1460.  
  1461.     // Find the best combination of:
  1462.     //      Adapter Ordinal
  1463.     //      Device Type
  1464.     //      Adapter Format
  1465.     //      Back Buffer Format
  1466.     //      Windowed
  1467.     // given what's available on the system and the match options combined with the device settings input.
  1468.     // This combination of settings is encapsulated by the CD3DEnumDeviceSettingsCombo class.
  1469.     float fBestRanking = -1.0f;
  1470.     CD3DEnumDeviceSettingsCombo* pBestDeviceSettingsCombo = NULL;
  1471.     D3DDISPLAYMODE adapterDesktopDisplayMode;
  1472.  
  1473.     CGrowableArray<CD3DEnumAdapterInfo*>* pAdapterList = pd3dEnum->GetAdapterInfoList();
  1474.     for( int iAdapter=0; iAdapter<pAdapterList->GetSize(); iAdapter++ )
  1475.     {
  1476.         CD3DEnumAdapterInfo* pAdapterInfo = pAdapterList->GetAt(iAdapter);
  1477.  
  1478.         // Get the desktop display mode of adapter 
  1479.         pD3D->GetAdapterDisplayMode( pAdapterInfo->AdapterOrdinal, &adapterDesktopDisplayMode );
  1480.  
  1481.         // Enum all the device types supported by this adapter to find the best device settings
  1482.         for( int iDeviceInfo=0; iDeviceInfo<pAdapterInfo->deviceInfoList.GetSize(); iDeviceInfo++ )
  1483.         {
  1484.             CD3DEnumDeviceInfo* pDeviceInfo = pAdapterInfo->deviceInfoList.GetAt(iDeviceInfo);
  1485.  
  1486.             // Enum all the device settings combinations.  A device settings combination is 
  1487.             // a unique set of an adapter format, back buffer format, and IsWindowed.
  1488.             for( int iDeviceCombo=0; iDeviceCombo<pDeviceInfo->deviceSettingsComboList.GetSize(); iDeviceCombo++ )
  1489.             {
  1490.                 CD3DEnumDeviceSettingsCombo* pDeviceSettingsCombo = pDeviceInfo->deviceSettingsComboList.GetAt(iDeviceCombo);
  1491.  
  1492.                 // If windowed mode the adapter format has to be the same as the desktop 
  1493.                 // display mode format so skip any that don't match
  1494.                 if (pDeviceSettingsCombo->Windowed && (pDeviceSettingsCombo->AdapterFormat != adapterDesktopDisplayMode.Format))
  1495.                     continue;
  1496.  
  1497.                 // Skip any combo that doesn't meet the preserve match options
  1498.                 if( false == DXUTDoesDeviceComboMatchPreserveOptions( pDeviceSettingsCombo, pIn, pMatchOptions ) )
  1499.                     continue;           
  1500.  
  1501.                 // Get a ranking number that describes how closely this device combo matches the optimal combo
  1502.                 float fCurRanking = DXUTRankDeviceCombo( pDeviceSettingsCombo, &optimalDeviceSettings, &adapterDesktopDisplayMode );
  1503.  
  1504.                 // If this combo better matches the input device settings then save it
  1505.                 if( fCurRanking > fBestRanking )
  1506.                 {
  1507.                     pBestDeviceSettingsCombo = pDeviceSettingsCombo;
  1508.                     fBestRanking = fCurRanking;
  1509.                 }                
  1510.             }
  1511.         }
  1512.     }
  1513.  
  1514.     // If no best device combination was found then fail
  1515.     if( pBestDeviceSettingsCombo == NULL ) 
  1516.         return DXUTERR_NOCOMPATIBLEDEVICES;
  1517.  
  1518.     // Using the best device settings combo found, build valid device settings taking heed of 
  1519.     // the match options and the input device settings
  1520.     DXUTDeviceSettings validDeviceSettings;
  1521.     DXUTBuildValidDeviceSettings( &validDeviceSettings, pBestDeviceSettingsCombo, pIn, pMatchOptions );
  1522.     *pOut = validDeviceSettings;
  1523.  
  1524.     return S_OK;
  1525. }
  1526.  
  1527.  
  1528. //--------------------------------------------------------------------------------------
  1529. // Internal helper function to build a device settings structure based upon the match 
  1530. // options.  If the match option is set to ignore, then a optimal default value is used.
  1531. // The default value may not exist on the system, but later this will be taken 
  1532. // into account.
  1533. //--------------------------------------------------------------------------------------
  1534. void DXUTBuildOptimalDeviceSettings( DXUTDeviceSettings* pOptimalDeviceSettings, 
  1535.                                      DXUTDeviceSettings* pDeviceSettingsIn, 
  1536.                                      DXUTMatchOptions* pMatchOptions )
  1537. {
  1538.     IDirect3D9* pD3D = DXUTGetD3DObject();
  1539.     D3DDISPLAYMODE adapterDesktopDisplayMode;
  1540.  
  1541.     ZeroMemory( pOptimalDeviceSettings, sizeof(DXUTDeviceSettings) ); 
  1542.  
  1543.     //---------------------
  1544.     // Adapter ordinal
  1545.     //---------------------    
  1546.     if( pMatchOptions->eAdapterOrdinal == DXUTMT_IGNORE_INPUT )
  1547.         pOptimalDeviceSettings->AdapterOrdinal = D3DADAPTER_DEFAULT; 
  1548.     else
  1549.         pOptimalDeviceSettings->AdapterOrdinal = pDeviceSettingsIn->AdapterOrdinal;      
  1550.  
  1551.     //---------------------
  1552.     // Device type
  1553.     //---------------------
  1554.     if( pMatchOptions->eDeviceType == DXUTMT_IGNORE_INPUT )
  1555.         pOptimalDeviceSettings->DeviceType = D3DDEVTYPE_HAL; 
  1556.     else
  1557.         pOptimalDeviceSettings->DeviceType = pDeviceSettingsIn->DeviceType;
  1558.  
  1559.     //---------------------
  1560.     // Windowed
  1561.     //---------------------
  1562.     if( pMatchOptions->eWindowed == DXUTMT_IGNORE_INPUT )
  1563.         pOptimalDeviceSettings->pp.Windowed = TRUE; 
  1564.     else
  1565.         pOptimalDeviceSettings->pp.Windowed = pDeviceSettingsIn->pp.Windowed;
  1566.  
  1567.     //---------------------
  1568.     // Adapter format
  1569.     //---------------------
  1570.     if( pMatchOptions->eAdapterFormat == DXUTMT_IGNORE_INPUT )
  1571.     {
  1572.         // If windowed, default to the desktop display mode
  1573.         // If fullscreen, default to the desktop display mode for quick mode change or 
  1574.         // default to D3DFMT_X8R8G8B8 if the desktop display mode is < 32bit
  1575.         pD3D->GetAdapterDisplayMode( pOptimalDeviceSettings->AdapterOrdinal, &adapterDesktopDisplayMode );
  1576.         if( pOptimalDeviceSettings->pp.Windowed || DXUTColorChannelBits(adapterDesktopDisplayMode.Format) >= 8 )
  1577.             pOptimalDeviceSettings->AdapterFormat = adapterDesktopDisplayMode.Format;
  1578.         else
  1579.             pOptimalDeviceSettings->AdapterFormat = D3DFMT_X8R8G8B8;
  1580.     }
  1581.     else
  1582.     {
  1583.         pOptimalDeviceSettings->AdapterFormat = pDeviceSettingsIn->AdapterFormat;
  1584.     }
  1585.  
  1586.     //---------------------
  1587.     // Vertex processing
  1588.     //---------------------
  1589.     if( pMatchOptions->eVertexProcessing == DXUTMT_IGNORE_INPUT )
  1590.         pOptimalDeviceSettings->BehaviorFlags = D3DCREATE_HARDWARE_VERTEXPROCESSING; 
  1591.     else
  1592.         pOptimalDeviceSettings->BehaviorFlags = pDeviceSettingsIn->BehaviorFlags;
  1593.  
  1594.     //---------------------
  1595.     // Resolution
  1596.     //---------------------
  1597.     if( pMatchOptions->eResolution == DXUTMT_IGNORE_INPUT )
  1598.     {
  1599.         // If windowed, default to 640x480
  1600.         // If fullscreen, default to the desktop res for quick mode change
  1601.         if( pOptimalDeviceSettings->pp.Windowed )
  1602.         {
  1603.             pOptimalDeviceSettings->pp.BackBufferWidth = 640;
  1604.             pOptimalDeviceSettings->pp.BackBufferHeight = 480;
  1605.         }
  1606.         else
  1607.         {
  1608.             pD3D->GetAdapterDisplayMode( pOptimalDeviceSettings->AdapterOrdinal, &adapterDesktopDisplayMode );
  1609.             pOptimalDeviceSettings->pp.BackBufferWidth = adapterDesktopDisplayMode.Width;
  1610.             pOptimalDeviceSettings->pp.BackBufferHeight = adapterDesktopDisplayMode.Height;
  1611.         }
  1612.     }
  1613.     else
  1614.     {
  1615.         pOptimalDeviceSettings->pp.BackBufferWidth = pDeviceSettingsIn->pp.BackBufferWidth;
  1616.         pOptimalDeviceSettings->pp.BackBufferHeight = pDeviceSettingsIn->pp.BackBufferHeight;
  1617.     }
  1618.  
  1619.     //---------------------
  1620.     // Back buffer format
  1621.     //---------------------
  1622.     if( pMatchOptions->eBackBufferFormat == DXUTMT_IGNORE_INPUT )
  1623.         pOptimalDeviceSettings->pp.BackBufferFormat = pOptimalDeviceSettings->AdapterFormat; // Default to match the adapter format
  1624.     else
  1625.         pOptimalDeviceSettings->pp.BackBufferFormat = pDeviceSettingsIn->pp.BackBufferFormat;
  1626.  
  1627.     //---------------------
  1628.     // Back buffer count
  1629.     //---------------------
  1630.     if( pMatchOptions->eBackBufferCount == DXUTMT_IGNORE_INPUT )
  1631.         pOptimalDeviceSettings->pp.BackBufferCount = 2; // Default to triple buffering for perf gain
  1632.     else
  1633.         pOptimalDeviceSettings->pp.BackBufferCount = pDeviceSettingsIn->pp.BackBufferCount;
  1634.    
  1635.     //---------------------
  1636.     // Multisample
  1637.     //---------------------
  1638.     if( pMatchOptions->eMultiSample == DXUTMT_IGNORE_INPUT )
  1639.     {
  1640.         // Default to no multisampling 
  1641.         pOptimalDeviceSettings->pp.MultiSampleType = D3DMULTISAMPLE_NONE;
  1642.         pOptimalDeviceSettings->pp.MultiSampleQuality = 0; 
  1643.     }
  1644.     else
  1645.     {
  1646.         pOptimalDeviceSettings->pp.MultiSampleType = pDeviceSettingsIn->pp.MultiSampleType;
  1647.         pOptimalDeviceSettings->pp.MultiSampleQuality = pDeviceSettingsIn->pp.MultiSampleQuality;
  1648.     }
  1649.  
  1650.     //---------------------
  1651.     // Swap effect
  1652.     //---------------------
  1653.     if( pMatchOptions->eSwapEffect == DXUTMT_IGNORE_INPUT )
  1654.         pOptimalDeviceSettings->pp.SwapEffect = D3DSWAPEFFECT_DISCARD; 
  1655.     else
  1656.         pOptimalDeviceSettings->pp.SwapEffect = pDeviceSettingsIn->pp.SwapEffect;
  1657.  
  1658.     //---------------------
  1659.     // Depth stencil 
  1660.     //---------------------
  1661.     if( pMatchOptions->eDepthFormat == DXUTMT_IGNORE_INPUT &&
  1662.         pMatchOptions->eStencilFormat == DXUTMT_IGNORE_INPUT )
  1663.     {
  1664.         UINT nBackBufferBits = DXUTColorChannelBits( pOptimalDeviceSettings->pp.BackBufferFormat );
  1665.         if( nBackBufferBits >= 8 )
  1666.             pOptimalDeviceSettings->pp.AutoDepthStencilFormat = D3DFMT_D32; 
  1667.         else
  1668.             pOptimalDeviceSettings->pp.AutoDepthStencilFormat = D3DFMT_D16; 
  1669.     }
  1670.     else
  1671.     {
  1672.         pOptimalDeviceSettings->pp.AutoDepthStencilFormat = pDeviceSettingsIn->pp.AutoDepthStencilFormat;
  1673.     }
  1674.  
  1675.     //---------------------
  1676.     // Present flags
  1677.     //---------------------
  1678.     if( pMatchOptions->ePresentFlags == DXUTMT_IGNORE_INPUT )
  1679.         pOptimalDeviceSettings->pp.Flags = D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL;
  1680.     else
  1681.         pOptimalDeviceSettings->pp.Flags = pDeviceSettingsIn->pp.Flags;
  1682.  
  1683.     //---------------------
  1684.     // Refresh rate
  1685.     //---------------------
  1686.     if( pMatchOptions->eRefreshRate == DXUTMT_IGNORE_INPUT )
  1687.         pOptimalDeviceSettings->pp.FullScreen_RefreshRateInHz = 0;
  1688.     else
  1689.         pOptimalDeviceSettings->pp.FullScreen_RefreshRateInHz = pDeviceSettingsIn->pp.FullScreen_RefreshRateInHz;
  1690.  
  1691.     //---------------------
  1692.     // Present interval
  1693.     //---------------------
  1694.     if( pMatchOptions->ePresentInterval == DXUTMT_IGNORE_INPUT )
  1695.     {
  1696.         // For windowed, default to D3DPRESENT_INTERVAL_IMMEDIATE
  1697.         // which will wait not for the vertical retrace period to prevent tearing, 
  1698.         // but may introduce tearing.
  1699.         // For full screen, default to D3DPRESENT_INTERVAL_DEFAULT 
  1700.         // which will wait for the vertical retrace period to prevent tearing.
  1701.         if( pOptimalDeviceSettings->pp.Windowed )
  1702.             pOptimalDeviceSettings->pp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
  1703.         else
  1704.             pOptimalDeviceSettings->pp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
  1705.     }
  1706.     else
  1707.     {
  1708.         pOptimalDeviceSettings->pp.PresentationInterval = pDeviceSettingsIn->pp.PresentationInterval;
  1709.     }
  1710. }
  1711.  
  1712.  
  1713. //--------------------------------------------------------------------------------------
  1714. // Returns false for any CD3DEnumDeviceSettingsCombo that doesn't meet the preserve 
  1715. // match options against the input pDeviceSettingsIn.
  1716. //--------------------------------------------------------------------------------------
  1717. bool DXUTDoesDeviceComboMatchPreserveOptions( CD3DEnumDeviceSettingsCombo* pDeviceSettingsCombo, 
  1718.                                                  DXUTDeviceSettings* pDeviceSettingsIn, 
  1719.                                                  DXUTMatchOptions* pMatchOptions )
  1720. {
  1721.     //---------------------
  1722.     // Adapter ordinal
  1723.     //---------------------
  1724.     if( pMatchOptions->eAdapterOrdinal == DXUTMT_PRESERVE_INPUT && 
  1725.         (pDeviceSettingsCombo->AdapterOrdinal != pDeviceSettingsIn->AdapterOrdinal) )
  1726.         return false;
  1727.  
  1728.     //---------------------
  1729.     // Device type
  1730.     //---------------------
  1731.     if( pMatchOptions->eDeviceType == DXUTMT_PRESERVE_INPUT && 
  1732.         (pDeviceSettingsCombo->DeviceType != pDeviceSettingsIn->DeviceType) )
  1733.         return false;
  1734.  
  1735.     //---------------------
  1736.     // Windowed
  1737.     //---------------------
  1738.     if( pMatchOptions->eWindowed == DXUTMT_PRESERVE_INPUT && 
  1739.         (pDeviceSettingsCombo->Windowed != pDeviceSettingsIn->pp.Windowed) )
  1740.         return false;
  1741.  
  1742.     //---------------------
  1743.     // Adapter format
  1744.     //---------------------
  1745.     if( pMatchOptions->eAdapterFormat == DXUTMT_PRESERVE_INPUT && 
  1746.         (pDeviceSettingsCombo->AdapterFormat != pDeviceSettingsIn->AdapterFormat) )
  1747.         return false;
  1748.  
  1749.     //---------------------
  1750.     // Vertex processing
  1751.     //---------------------
  1752.     // If keep VP and input has HWVP, then skip if this combo doesn't have HWTL 
  1753.     if( pMatchOptions->eVertexProcessing == DXUTMT_PRESERVE_INPUT && 
  1754.         ((pDeviceSettingsIn->BehaviorFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING) != 0) && 
  1755.         ((pDeviceSettingsCombo->pDeviceInfo->Caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) == 0) )
  1756.         return false;
  1757.  
  1758.     //---------------------
  1759.     // Resolution
  1760.     //---------------------
  1761.     // If keep resolution then check that width and height supported by this combo
  1762.     if( pMatchOptions->eResolution == DXUTMT_PRESERVE_INPUT )
  1763.     {
  1764.         bool bFound = false;
  1765.         for( int i=0; i< pDeviceSettingsCombo->pAdapterInfo->displayModeList.GetSize(); i++ )
  1766.         {
  1767.             D3DDISPLAYMODE displayMode = pDeviceSettingsCombo->pAdapterInfo->displayModeList.GetAt( i );
  1768.             if( displayMode.Format != pDeviceSettingsCombo->AdapterFormat )
  1769.                 continue; // Skip this display mode if it doesn't match the combo's adapter format
  1770.  
  1771.             if( displayMode.Width == pDeviceSettingsIn->pp.BackBufferWidth &&
  1772.                 displayMode.Height == pDeviceSettingsIn->pp.BackBufferHeight )
  1773.             {
  1774.                 bFound = true;
  1775.                 break;
  1776.             }
  1777.         }
  1778.  
  1779.         // If the width and height are not supported by this combo, return false
  1780.         if( !bFound )
  1781.             return false;
  1782.     }
  1783.  
  1784.     //---------------------
  1785.     // Back buffer format
  1786.     //---------------------
  1787.     if( pMatchOptions->eBackBufferFormat == DXUTMT_PRESERVE_INPUT && 
  1788.         pDeviceSettingsCombo->BackBufferFormat != pDeviceSettingsIn->pp.BackBufferFormat )
  1789.         return false;
  1790.  
  1791.     //---------------------
  1792.     // Back buffer count
  1793.     //---------------------
  1794.     // No caps for the back buffer count
  1795.  
  1796.     //---------------------
  1797.     // Multisample
  1798.     //---------------------
  1799.     if( pMatchOptions->eMultiSample == DXUTMT_PRESERVE_INPUT )
  1800.     {
  1801.         bool bFound = false;
  1802.         for( int i=0; i<pDeviceSettingsCombo->multiSampleTypeList.GetSize(); i++ )
  1803.         {
  1804.             D3DMULTISAMPLE_TYPE msType = pDeviceSettingsCombo->multiSampleTypeList.GetAt(i);
  1805.             DWORD msQuality  = pDeviceSettingsCombo->multiSampleQualityList.GetAt(i);
  1806.  
  1807.             if( msType == pDeviceSettingsIn->pp.MultiSampleType &&
  1808.                 msQuality >= pDeviceSettingsIn->pp.MultiSampleQuality )
  1809.             {
  1810.                 bFound = true;
  1811.                 break;
  1812.             }
  1813.         }
  1814.  
  1815.         // If multisample type/quality not supported by this combo, then return false
  1816.         if( !bFound )
  1817.             return false;
  1818.     }
  1819.         
  1820.     //---------------------
  1821.     // Swap effect
  1822.     //---------------------
  1823.     // No caps for swap effects
  1824.  
  1825.     //---------------------
  1826.     // Depth stencil 
  1827.     //---------------------
  1828.     // If keep depth stencil format then check that the depth stencil format is supported by this combo
  1829.     if( pMatchOptions->eDepthFormat == DXUTMT_PRESERVE_INPUT &&
  1830.         pMatchOptions->eStencilFormat == DXUTMT_PRESERVE_INPUT )
  1831.     {
  1832.         if( pDeviceSettingsIn->pp.AutoDepthStencilFormat != D3DFMT_UNKNOWN &&
  1833.             !pDeviceSettingsCombo->depthStencilFormatList.Contains( pDeviceSettingsIn->pp.AutoDepthStencilFormat ) )
  1834.             return false;
  1835.     }
  1836.  
  1837.     // If keep depth format then check that the depth format is supported by this combo
  1838.     if( pMatchOptions->eDepthFormat == DXUTMT_PRESERVE_INPUT &&
  1839.         pDeviceSettingsIn->pp.AutoDepthStencilFormat != D3DFMT_UNKNOWN )
  1840.     {
  1841.         bool bFound = false;
  1842.         UINT dwDepthBits = DXUTDepthBits( pDeviceSettingsIn->pp.AutoDepthStencilFormat );
  1843.         for( int i=0; i<pDeviceSettingsCombo->depthStencilFormatList.GetSize(); i++ )
  1844.         {
  1845.             D3DFORMAT depthStencilFmt = pDeviceSettingsCombo->depthStencilFormatList.GetAt(i);
  1846.             UINT dwCurDepthBits = DXUTDepthBits( depthStencilFmt );
  1847.             if( dwCurDepthBits - dwDepthBits == 0)
  1848.                 bFound = true;
  1849.         }
  1850.  
  1851.         if( !bFound )
  1852.             return false;
  1853.     }
  1854.  
  1855.     // If keep depth format then check that the depth format is supported by this combo
  1856.     if( pMatchOptions->eStencilFormat == DXUTMT_PRESERVE_INPUT &&
  1857.         pDeviceSettingsIn->pp.AutoDepthStencilFormat != D3DFMT_UNKNOWN )
  1858.     {
  1859.         bool bFound = false;
  1860.         UINT dwStencilBits = DXUTStencilBits( pDeviceSettingsIn->pp.AutoDepthStencilFormat );
  1861.         for( int i=0; i<pDeviceSettingsCombo->depthStencilFormatList.GetSize(); i++ )
  1862.         {
  1863.             D3DFORMAT depthStencilFmt = pDeviceSettingsCombo->depthStencilFormatList.GetAt(i);
  1864.             UINT dwCurStencilBits = DXUTStencilBits( depthStencilFmt );
  1865.             if( dwCurStencilBits - dwStencilBits == 0)
  1866.                 bFound = true;
  1867.         }
  1868.  
  1869.         if( !bFound )
  1870.             return false;
  1871.     }
  1872.  
  1873.     //---------------------
  1874.     // Present flags
  1875.     //---------------------
  1876.     // No caps for the present flags
  1877.  
  1878.     //---------------------
  1879.     // Refresh rate
  1880.     //---------------------
  1881.     // If keep refresh rate then check that the resolution is supported by this combo
  1882.     if( pMatchOptions->eRefreshRate == DXUTMT_PRESERVE_INPUT )
  1883.     {
  1884.         bool bFound = false;
  1885.         for( int i=0; i<pDeviceSettingsCombo->pAdapterInfo->displayModeList.GetSize(); i++ )
  1886.         {
  1887.             D3DDISPLAYMODE displayMode = pDeviceSettingsCombo->pAdapterInfo->displayModeList.GetAt( i );
  1888.             if( displayMode.Format != pDeviceSettingsCombo->AdapterFormat )
  1889.                 continue;
  1890.             if( displayMode.RefreshRate == pDeviceSettingsIn->pp.FullScreen_RefreshRateInHz )
  1891.             {
  1892.                 bFound = true;
  1893.                 break;
  1894.             }
  1895.         }
  1896.  
  1897.         // If refresh rate not supported by this combo, then return false
  1898.         if( !bFound )
  1899.             return false;
  1900.     }
  1901.  
  1902.     //---------------------
  1903.     // Present interval
  1904.     //---------------------
  1905.     // If keep present interval then check that the present interval is supported by this combo
  1906.     if( pMatchOptions->ePresentInterval == DXUTMT_PRESERVE_INPUT &&
  1907.         !pDeviceSettingsCombo->presentIntervalList.Contains( pDeviceSettingsIn->pp.PresentationInterval ) )
  1908.         return false;
  1909.  
  1910.     return true;
  1911. }
  1912.  
  1913.  
  1914. //--------------------------------------------------------------------------------------
  1915. // Returns a ranking number that describes how closely this device 
  1916. // combo matches the optimal combo based on the match options and the optimal device settings
  1917. //--------------------------------------------------------------------------------------
  1918. float DXUTRankDeviceCombo( CD3DEnumDeviceSettingsCombo* pDeviceSettingsCombo, 
  1919.                            DXUTDeviceSettings* pOptimalDeviceSettings,
  1920.                            D3DDISPLAYMODE* pAdapterDesktopDisplayMode )
  1921. {
  1922.     float fCurRanking = 0.0f; 
  1923.  
  1924.     // Arbitrary weights.  Gives preference to the ordinal, device type, and windowed
  1925.     const float fAdapterOrdinalWeight   = 1000.0f;
  1926.     const float fDeviceTypeWeight       = 100.0f;
  1927.     const float fWindowWeight           = 10.0f;
  1928.     const float fAdapterFormatWeight    = 1.0f;
  1929.     const float fVertexProcessingWeight = 1.0f;
  1930.     const float fResolutionWeight       = 1.0f;
  1931.     const float fBackBufferFormatWeight = 1.0f;
  1932.     const float fMultiSampleWeight      = 1.0f;
  1933.     const float fDepthStencilWeight     = 1.0f;
  1934.     const float fRefreshRateWeight      = 1.0f;
  1935.     const float fPresentIntervalWeight  = 1.0f;
  1936.  
  1937.     //---------------------
  1938.     // Adapter ordinal
  1939.     //---------------------
  1940.     if( pDeviceSettingsCombo->AdapterOrdinal == pOptimalDeviceSettings->AdapterOrdinal )
  1941.         fCurRanking += fAdapterOrdinalWeight;
  1942.  
  1943.     //---------------------
  1944.     // Device type
  1945.     //---------------------
  1946.     if( pDeviceSettingsCombo->DeviceType == pOptimalDeviceSettings->DeviceType )
  1947.         fCurRanking += fDeviceTypeWeight;
  1948.     // Slightly prefer HAL 
  1949.     if( pDeviceSettingsCombo->DeviceType == D3DDEVTYPE_HAL )
  1950.         fCurRanking += 0.1f; 
  1951.  
  1952.     //---------------------
  1953.     // Windowed
  1954.     //---------------------
  1955.     if( pDeviceSettingsCombo->Windowed == pOptimalDeviceSettings->pp.Windowed )
  1956.         fCurRanking += fWindowWeight;
  1957.  
  1958.     //---------------------
  1959.     // Adapter format
  1960.     //---------------------
  1961.     if( pDeviceSettingsCombo->AdapterFormat == pOptimalDeviceSettings->AdapterFormat )
  1962.     {
  1963.         fCurRanking += fAdapterFormatWeight;
  1964.     }
  1965.     else
  1966.     {
  1967.         int nBitDepthDelta = abs( (long) DXUTColorChannelBits(pDeviceSettingsCombo->AdapterFormat) -
  1968.                                   (long) DXUTColorChannelBits(pOptimalDeviceSettings->AdapterFormat) );
  1969.         float fScale = max(0.9f - (float)nBitDepthDelta*0.2f, 0);
  1970.         fCurRanking += fScale * fAdapterFormatWeight;
  1971.     }
  1972.  
  1973.     if( !pDeviceSettingsCombo->Windowed )
  1974.     {
  1975.         // Slightly prefer when it matches the desktop format or is D3DFMT_X8R8G8B8
  1976.         bool bAdapterOptimalMatch;
  1977.         if( DXUTColorChannelBits(pAdapterDesktopDisplayMode->Format) >= 8 )
  1978.             bAdapterOptimalMatch = (pDeviceSettingsCombo->AdapterFormat == pAdapterDesktopDisplayMode->Format);
  1979.         else
  1980.             bAdapterOptimalMatch = (pDeviceSettingsCombo->AdapterFormat == D3DFMT_X8R8G8B8);
  1981.  
  1982.         if( bAdapterOptimalMatch )
  1983.             fCurRanking += 0.1f;
  1984.     }
  1985.  
  1986.     //---------------------
  1987.     // Vertex processing
  1988.     //---------------------
  1989.     if( (pOptimalDeviceSettings->BehaviorFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING) != 0 || 
  1990.         (pOptimalDeviceSettings->BehaviorFlags & D3DCREATE_MIXED_VERTEXPROCESSING) != 0 )
  1991.     {
  1992.         if( (pDeviceSettingsCombo->pDeviceInfo->Caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) != 0 )
  1993.             fCurRanking += fVertexProcessingWeight;
  1994.     }
  1995.     // Slightly prefer HW T&L
  1996.     if( (pDeviceSettingsCombo->pDeviceInfo->Caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) != 0 )
  1997.         fCurRanking += 0.1f;
  1998.  
  1999.     //---------------------
  2000.     // Resolution
  2001.     //---------------------
  2002.     bool bResolutionFound = false;
  2003.     for( int idm = 0; idm < pDeviceSettingsCombo->pAdapterInfo->displayModeList.GetSize(); idm++ )
  2004.     {
  2005.         D3DDISPLAYMODE displayMode = pDeviceSettingsCombo->pAdapterInfo->displayModeList.GetAt( idm );
  2006.         if( displayMode.Format != pDeviceSettingsCombo->AdapterFormat )
  2007.             continue;
  2008.         if( displayMode.Width == pOptimalDeviceSettings->pp.BackBufferWidth &&
  2009.             displayMode.Height == pOptimalDeviceSettings->pp.BackBufferHeight )
  2010.             bResolutionFound = true;
  2011.     }
  2012.     if( bResolutionFound )
  2013.         fCurRanking += fResolutionWeight;
  2014.  
  2015.     //---------------------
  2016.     // Back buffer format
  2017.     //---------------------
  2018.     if( pDeviceSettingsCombo->BackBufferFormat == pOptimalDeviceSettings->pp.BackBufferFormat )
  2019.     {
  2020.         fCurRanking += fBackBufferFormatWeight;
  2021.     }
  2022.     else
  2023.     {
  2024.         int nBitDepthDelta = abs( (long) DXUTColorChannelBits(pDeviceSettingsCombo->BackBufferFormat) -
  2025.                                   (long) DXUTColorChannelBits(pOptimalDeviceSettings->pp.BackBufferFormat) );
  2026.         float fScale = max(0.9f - (float)nBitDepthDelta*0.2f, 0);
  2027.         fCurRanking += fScale * fBackBufferFormatWeight;
  2028.     }
  2029.  
  2030.     // Check if this back buffer format is the same as 
  2031.     // the adapter format since this is preferred.
  2032.     bool bAdapterMatchesBB = (pDeviceSettingsCombo->BackBufferFormat == pDeviceSettingsCombo->AdapterFormat);
  2033.     if( bAdapterMatchesBB )
  2034.         fCurRanking += 0.1f;
  2035.  
  2036.     //---------------------
  2037.     // Back buffer count
  2038.     //---------------------
  2039.     // No caps for the back buffer count
  2040.  
  2041.     //---------------------
  2042.     // Multisample
  2043.     //---------------------
  2044.     bool bMultiSampleFound = false;
  2045.     for( int i=0; i<pDeviceSettingsCombo->multiSampleTypeList.GetSize(); i++ )
  2046.     {
  2047.         D3DMULTISAMPLE_TYPE msType = pDeviceSettingsCombo->multiSampleTypeList.GetAt(i);
  2048.         DWORD msQuality  = pDeviceSettingsCombo->multiSampleQualityList.GetAt(i);
  2049.  
  2050.         if( msType == pOptimalDeviceSettings->pp.MultiSampleType &&
  2051.             msQuality >= pOptimalDeviceSettings->pp.MultiSampleQuality )
  2052.         {
  2053.             bMultiSampleFound = true;
  2054.             break;
  2055.         }
  2056.     }
  2057.     if( bMultiSampleFound )
  2058.         fCurRanking += fMultiSampleWeight;
  2059.         
  2060.     //---------------------
  2061.     // Swap effect
  2062.     //---------------------
  2063.     // No caps for swap effects
  2064.  
  2065.     //---------------------
  2066.     // Depth stencil 
  2067.     //---------------------
  2068.     if( pDeviceSettingsCombo->depthStencilFormatList.Contains( pOptimalDeviceSettings->pp.AutoDepthStencilFormat ) )
  2069.         fCurRanking += fDepthStencilWeight;
  2070.  
  2071.     //---------------------
  2072.     // Present flags
  2073.     //---------------------
  2074.     // No caps for the present flags
  2075.  
  2076.     //---------------------
  2077.     // Refresh rate
  2078.     //---------------------
  2079.     bool bRefreshFound = false;
  2080.     for( int idm = 0; idm < pDeviceSettingsCombo->pAdapterInfo->displayModeList.GetSize(); idm++ )
  2081.     {
  2082.         D3DDISPLAYMODE displayMode = pDeviceSettingsCombo->pAdapterInfo->displayModeList.GetAt( idm );
  2083.         if( displayMode.Format != pDeviceSettingsCombo->AdapterFormat )
  2084.             continue;
  2085.         if( displayMode.RefreshRate == pOptimalDeviceSettings->pp.FullScreen_RefreshRateInHz )
  2086.             bRefreshFound = true;
  2087.     }
  2088.     if( bRefreshFound )
  2089.         fCurRanking += fRefreshRateWeight;
  2090.  
  2091.     //---------------------
  2092.     // Present interval
  2093.     //---------------------
  2094.     // If keep present interval then check that the present interval is supported by this combo
  2095.     if( pDeviceSettingsCombo->presentIntervalList.Contains( pOptimalDeviceSettings->pp.PresentationInterval ) )
  2096.         fCurRanking += fPresentIntervalWeight;
  2097.  
  2098.     return fCurRanking;
  2099. }
  2100.  
  2101.  
  2102. //--------------------------------------------------------------------------------------
  2103. // Builds valid device settings using the match options, the input device settings, and the 
  2104. // best device settings combo found.
  2105. //--------------------------------------------------------------------------------------
  2106. void DXUTBuildValidDeviceSettings( DXUTDeviceSettings* pValidDeviceSettings, 
  2107.                                    CD3DEnumDeviceSettingsCombo* pBestDeviceSettingsCombo, 
  2108.                                    DXUTDeviceSettings* pDeviceSettingsIn, 
  2109.                                    DXUTMatchOptions* pMatchOptions )
  2110. {
  2111.     IDirect3D9* pD3D = DXUTGetD3DObject();
  2112.     D3DDISPLAYMODE adapterDesktopDisplayMode;
  2113.     pD3D->GetAdapterDisplayMode( pBestDeviceSettingsCombo->AdapterOrdinal, &adapterDesktopDisplayMode );
  2114.  
  2115.     // For each setting pick the best, taking into account the match options and 
  2116.     // what's supported by the device
  2117.  
  2118.     //---------------------
  2119.     // Adapter Ordinal
  2120.     //---------------------
  2121.     // Just using pBestDeviceSettingsCombo->AdapterOrdinal
  2122.  
  2123.     //---------------------
  2124.     // Device Type
  2125.     //---------------------
  2126.     // Just using pBestDeviceSettingsCombo->DeviceType
  2127.  
  2128.     //---------------------
  2129.     // Windowed 
  2130.     //---------------------
  2131.     // Just using pBestDeviceSettingsCombo->Windowed
  2132.  
  2133.     //---------------------
  2134.     // Adapter Format
  2135.     //---------------------
  2136.     // Just using pBestDeviceSettingsCombo->AdapterFormat
  2137.  
  2138.     //---------------------
  2139.     // Vertex processing
  2140.     //---------------------
  2141.     DWORD dwBestBehaviorFlags = 0;
  2142.     if( pMatchOptions->eVertexProcessing == DXUTMT_PRESERVE_INPUT )   
  2143.     {
  2144.         dwBestBehaviorFlags = pDeviceSettingsIn->BehaviorFlags;
  2145.     }
  2146.     else if( pMatchOptions->eVertexProcessing == DXUTMT_IGNORE_INPUT )    
  2147.     {
  2148.         // The framework defaults to HWVP if available otherwise use SWVP
  2149.         if ((pBestDeviceSettingsCombo->pDeviceInfo->Caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) != 0)
  2150.             dwBestBehaviorFlags |= D3DCREATE_HARDWARE_VERTEXPROCESSING;
  2151.         else
  2152.             dwBestBehaviorFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
  2153.     }
  2154.     else // if( pMatchOptions->eVertexProcessing == DXUTMT_CLOSEST_TO_INPUT )    
  2155.     {
  2156.         // Default to input, and fallback to SWVP if HWVP not available 
  2157.         dwBestBehaviorFlags = pDeviceSettingsIn->BehaviorFlags;
  2158.         if ((pBestDeviceSettingsCombo->pDeviceInfo->Caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) == 0 && 
  2159.             ( (dwBestBehaviorFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING) != 0 || 
  2160.               (dwBestBehaviorFlags & D3DCREATE_MIXED_VERTEXPROCESSING) != 0) )
  2161.         {
  2162.             dwBestBehaviorFlags &= ~D3DCREATE_HARDWARE_VERTEXPROCESSING;
  2163.             dwBestBehaviorFlags &= ~D3DCREATE_MIXED_VERTEXPROCESSING;
  2164.             dwBestBehaviorFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
  2165.         }
  2166.  
  2167.         // One of these must be selected
  2168.         if( (dwBestBehaviorFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING) == 0 &&
  2169.             (dwBestBehaviorFlags & D3DCREATE_MIXED_VERTEXPROCESSING) == 0 &&
  2170.             (dwBestBehaviorFlags & D3DCREATE_SOFTWARE_VERTEXPROCESSING) == 0 )
  2171.         {
  2172.             if ((pBestDeviceSettingsCombo->pDeviceInfo->Caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) != 0)
  2173.                 dwBestBehaviorFlags |= D3DCREATE_HARDWARE_VERTEXPROCESSING;
  2174.             else
  2175.                 dwBestBehaviorFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
  2176.         }
  2177.     }
  2178.  
  2179.     //---------------------
  2180.     // Resolution
  2181.     //---------------------
  2182.     D3DDISPLAYMODE bestDisplayMode;  
  2183.     if( pMatchOptions->eResolution == DXUTMT_PRESERVE_INPUT )   
  2184.     {
  2185.         bestDisplayMode.Width = pDeviceSettingsIn->pp.BackBufferWidth;
  2186.         bestDisplayMode.Height = pDeviceSettingsIn->pp.BackBufferHeight;
  2187.     }
  2188.     else 
  2189.     {
  2190.         D3DDISPLAYMODE displayModeIn;  
  2191.         if( pMatchOptions->eResolution == DXUTMT_CLOSEST_TO_INPUT &&
  2192.             pDeviceSettingsIn && (pDeviceSettingsIn->pp.BackBufferWidth != 0 && pDeviceSettingsIn->pp.BackBufferWidth != 0) )   
  2193.         {
  2194.             displayModeIn.Width = pDeviceSettingsIn->pp.BackBufferWidth;
  2195.             displayModeIn.Height = pDeviceSettingsIn->pp.BackBufferHeight;
  2196.         }
  2197.         else // if( pMatchOptions->eResolution == DXUTMT_IGNORE_INPUT )   
  2198.         {
  2199.             if( pBestDeviceSettingsCombo->Windowed )
  2200.             {
  2201.                 // The framework defaults to 640x480 for windowed
  2202.                 displayModeIn.Width = 640;
  2203.                 displayModeIn.Height = 480;
  2204.             }
  2205.             else
  2206.             {
  2207.                 // The framework defaults to desktop resolution for fullscreen to try to avoid slow mode change
  2208.                 displayModeIn.Width = adapterDesktopDisplayMode.Width;
  2209.                 displayModeIn.Height = adapterDesktopDisplayMode.Height;
  2210.             }
  2211.         }
  2212.  
  2213.         // Call a helper function to find the closest valid display mode to the optimal 
  2214.         DXUTFindValidResolution( pBestDeviceSettingsCombo, displayModeIn, &bestDisplayMode );
  2215.     }
  2216.  
  2217.     //---------------------
  2218.     // Back Buffer Format
  2219.     //---------------------
  2220.     // Just using pBestDeviceSettingsCombo->BackBufferFormat
  2221.  
  2222.     //---------------------
  2223.     // Back buffer count
  2224.     //---------------------
  2225.     UINT bestBackBufferCount;
  2226.     if( pMatchOptions->eBackBufferCount == DXUTMT_PRESERVE_INPUT )   
  2227.     {
  2228.         bestBackBufferCount = pDeviceSettingsIn->pp.BackBufferCount;
  2229.     }
  2230.     else if( pMatchOptions->eBackBufferCount == DXUTMT_IGNORE_INPUT )   
  2231.     {
  2232.         // The framework defaults to triple buffering 
  2233.         bestBackBufferCount = 2;
  2234.     }
  2235.     else // if( pMatchOptions->eBackBufferCount == DXUTMT_CLOSEST_TO_INPUT )   
  2236.     {
  2237.         bestBackBufferCount = pDeviceSettingsIn->pp.BackBufferCount;
  2238.         if( bestBackBufferCount > 3 )
  2239.             bestBackBufferCount = 3;
  2240.         if( bestBackBufferCount < 1 )
  2241.             bestBackBufferCount = 1;
  2242.     }
  2243.     
  2244.     //---------------------
  2245.     // Multisample
  2246.     //---------------------
  2247.     D3DMULTISAMPLE_TYPE bestMultiSampleType;
  2248.     DWORD bestMultiSampleQuality;
  2249.     if( pDeviceSettingsIn && pDeviceSettingsIn->pp.SwapEffect != D3DSWAPEFFECT_DISCARD )
  2250.     {
  2251.         // Swap effect is not set to discard so multisampling has to off
  2252.         bestMultiSampleType = D3DMULTISAMPLE_NONE;
  2253.         bestMultiSampleQuality = 0;
  2254.     }
  2255.     else
  2256.     {
  2257.         if( pMatchOptions->eBackBufferCount == DXUTMT_PRESERVE_INPUT )   
  2258.         {
  2259.             bestMultiSampleType    = pDeviceSettingsIn->pp.MultiSampleType;
  2260.             bestMultiSampleQuality = pDeviceSettingsIn->pp.MultiSampleQuality;
  2261.         }
  2262.         else if( pMatchOptions->eBackBufferCount == DXUTMT_IGNORE_INPUT )   
  2263.         {
  2264.             // Default to no multisampling (always supported)
  2265.             bestMultiSampleType = D3DMULTISAMPLE_NONE;
  2266.             bestMultiSampleQuality = 0;
  2267.         }
  2268.         else if( pMatchOptions->eBackBufferCount == DXUTMT_CLOSEST_TO_INPUT )   
  2269.         {
  2270.             // Default to no multisampling (always supported)
  2271.             bestMultiSampleType = D3DMULTISAMPLE_NONE;
  2272.             bestMultiSampleQuality = 0;
  2273.  
  2274.             for( int i=0; i < pBestDeviceSettingsCombo->multiSampleTypeList.GetSize(); i++ )
  2275.             {
  2276.                 D3DMULTISAMPLE_TYPE type = pBestDeviceSettingsCombo->multiSampleTypeList.GetAt(i);
  2277.                 DWORD qualityLevels = pBestDeviceSettingsCombo->multiSampleQualityList.GetAt(i);
  2278.                 
  2279.                 // Check whether supported type is closer to the input than our current best
  2280.                 if( abs(type - pDeviceSettingsIn->pp.MultiSampleType) < abs(bestMultiSampleType - pDeviceSettingsIn->pp.MultiSampleType) )
  2281.                 {
  2282.                     bestMultiSampleType = type; 
  2283.                     bestMultiSampleQuality = min( qualityLevels-1, pDeviceSettingsIn->pp.MultiSampleQuality );
  2284.                 }
  2285.             }
  2286.         }
  2287.         else
  2288.         {
  2289.             // Error case
  2290.             bestMultiSampleType = D3DMULTISAMPLE_NONE;
  2291.             bestMultiSampleQuality = 0;
  2292.         }
  2293.     }
  2294.  
  2295.     //---------------------
  2296.     // Swap effect
  2297.     //---------------------
  2298.     D3DSWAPEFFECT bestSwapEffect;
  2299.     if( pMatchOptions->eSwapEffect == DXUTMT_PRESERVE_INPUT )   
  2300.     {
  2301.         bestSwapEffect = pDeviceSettingsIn->pp.SwapEffect;
  2302.     }
  2303.     else if( pMatchOptions->eSwapEffect == DXUTMT_IGNORE_INPUT )   
  2304.     {
  2305.         bestSwapEffect = D3DSWAPEFFECT_DISCARD;
  2306.     }
  2307.     else // if( pMatchOptions->eSwapEffect == DXUTMT_CLOSEST_TO_INPUT )   
  2308.     {
  2309.         bestSwapEffect = pDeviceSettingsIn->pp.SwapEffect;
  2310.  
  2311.         // Swap effect has to be one of these 3
  2312.         if( bestSwapEffect != D3DSWAPEFFECT_DISCARD &&
  2313.             bestSwapEffect != D3DSWAPEFFECT_FLIP &&
  2314.             bestSwapEffect != D3DSWAPEFFECT_COPY )
  2315.         {
  2316.             bestSwapEffect = D3DSWAPEFFECT_DISCARD;
  2317.         }
  2318.     }
  2319.  
  2320.     //---------------------
  2321.     // Depth stencil 
  2322.     //---------------------
  2323.     D3DFORMAT bestDepthStencilFormat;
  2324.     BOOL bestEnableAutoDepthStencil;
  2325.  
  2326.     CGrowableArray< int > depthStencilRanking;
  2327.     depthStencilRanking.SetSize( pBestDeviceSettingsCombo->depthStencilFormatList.GetSize() );
  2328.  
  2329.     UINT dwBackBufferBitDepth = DXUTColorChannelBits( pBestDeviceSettingsCombo->BackBufferFormat );       
  2330.     UINT dwInputDepthBitDepth = 0;
  2331.     if( pDeviceSettingsIn )
  2332.         dwInputDepthBitDepth = DXUTDepthBits( pDeviceSettingsIn->pp.AutoDepthStencilFormat );
  2333.  
  2334.     for( int i=0; i<pBestDeviceSettingsCombo->depthStencilFormatList.GetSize(); i++ )
  2335.     {
  2336.         D3DFORMAT curDepthStencilFmt = pBestDeviceSettingsCombo->depthStencilFormatList.GetAt(i);
  2337.         DWORD dwCurDepthBitDepth = DXUTDepthBits( curDepthStencilFmt );
  2338.         int nRanking;
  2339.  
  2340.         if( pMatchOptions->eDepthFormat == DXUTMT_PRESERVE_INPUT )
  2341.         {                       
  2342.             // Need to match bit depth of input
  2343.             if(dwCurDepthBitDepth == dwInputDepthBitDepth)
  2344.                 nRanking = 0;
  2345.             else
  2346.                 nRanking = 10000;
  2347.         }
  2348.         else if( pMatchOptions->eDepthFormat == DXUTMT_IGNORE_INPUT )
  2349.         {
  2350.             // Prefer match of backbuffer bit depth
  2351.             nRanking = abs((int)dwCurDepthBitDepth - (int)dwBackBufferBitDepth*4);
  2352.         }
  2353.         else // if( pMatchOptions->eDepthFormat == DXUTMT_CLOSEST_TO_INPUT )
  2354.         {
  2355.             // Prefer match of input depth format bit depth
  2356.             nRanking = abs((int)dwCurDepthBitDepth - (int)dwInputDepthBitDepth);
  2357.         }
  2358.  
  2359.         depthStencilRanking.Add( nRanking );
  2360.     }
  2361.  
  2362.     UINT dwInputStencilBitDepth = 0;
  2363.     if( pDeviceSettingsIn )
  2364.         dwInputStencilBitDepth = DXUTStencilBits( pDeviceSettingsIn->pp.AutoDepthStencilFormat );
  2365.  
  2366.     for( int i=0; i<pBestDeviceSettingsCombo->depthStencilFormatList.GetSize(); i++ )
  2367.     {
  2368.         D3DFORMAT curDepthStencilFmt = pBestDeviceSettingsCombo->depthStencilFormatList.GetAt(i);
  2369.         int nRanking = depthStencilRanking.GetAt(i);
  2370.         DWORD dwCurStencilBitDepth = DXUTStencilBits( curDepthStencilFmt );
  2371.  
  2372.         if( pMatchOptions->eStencilFormat == DXUTMT_PRESERVE_INPUT )
  2373.         {                       
  2374.             // Need to match bit depth of input
  2375.             if(dwCurStencilBitDepth == dwInputStencilBitDepth)
  2376.                 nRanking += 0;
  2377.             else
  2378.                 nRanking += 10000;
  2379.         }
  2380.         else if( pMatchOptions->eStencilFormat == DXUTMT_IGNORE_INPUT )
  2381.         {
  2382.             // Prefer 0 stencil bit depth
  2383.             nRanking += dwCurStencilBitDepth;
  2384.         }
  2385.         else // if( pMatchOptions->eStencilFormat == DXUTMT_CLOSEST_TO_INPUT )
  2386.         {
  2387.             // Prefer match of input stencil format bit depth
  2388.             nRanking += abs((int)dwCurStencilBitDepth - (int)dwInputStencilBitDepth);
  2389.         }
  2390.  
  2391.         depthStencilRanking.SetAt( i, nRanking );
  2392.     }
  2393.  
  2394.     int nBestRanking = 100000;
  2395.     int nBestIndex = -1;
  2396.     for( int i=0; i<pBestDeviceSettingsCombo->depthStencilFormatList.GetSize(); i++ )
  2397.     {
  2398.         int nRanking = depthStencilRanking.GetAt(i);
  2399.         if( nRanking < nBestRanking )
  2400.         {
  2401.             nBestRanking = nRanking;
  2402.             nBestIndex = i;
  2403.         }
  2404.     }
  2405.  
  2406.     if( nBestIndex >= 0 )
  2407.     {
  2408.         bestDepthStencilFormat = pBestDeviceSettingsCombo->depthStencilFormatList.GetAt(nBestIndex);
  2409.         bestEnableAutoDepthStencil = true;
  2410.     }
  2411.     else
  2412.     {
  2413.         bestDepthStencilFormat = D3DFMT_UNKNOWN;
  2414.         bestEnableAutoDepthStencil = false;
  2415.     }
  2416.  
  2417.  
  2418.     //---------------------
  2419.     // Present flags
  2420.     //---------------------
  2421.     DWORD dwBestFlags;
  2422.     if( pMatchOptions->ePresentFlags == DXUTMT_PRESERVE_INPUT )   
  2423.     {
  2424.         dwBestFlags = pDeviceSettingsIn->pp.Flags;
  2425.     }
  2426.     else if( pMatchOptions->ePresentFlags == DXUTMT_IGNORE_INPUT )   
  2427.     {
  2428.         dwBestFlags = 0;
  2429.         if( bestEnableAutoDepthStencil )
  2430.             dwBestFlags = D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL;            
  2431.     }
  2432.     else // if( pMatchOptions->ePresentFlags == DXUTMT_CLOSEST_TO_INPUT )   
  2433.     {
  2434.         dwBestFlags = pDeviceSettingsIn->pp.Flags;
  2435.         if( bestEnableAutoDepthStencil )
  2436.             dwBestFlags |= D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL;
  2437.     }
  2438.  
  2439.     //---------------------
  2440.     // Refresh rate
  2441.     //---------------------
  2442.     if( pBestDeviceSettingsCombo->Windowed )
  2443.     {
  2444.         // Must be 0 for windowed
  2445.         bestDisplayMode.RefreshRate = 0;
  2446.     }
  2447.     else
  2448.     {
  2449.         if( pMatchOptions->eRefreshRate == DXUTMT_PRESERVE_INPUT )   
  2450.         {
  2451.             bestDisplayMode.RefreshRate = pDeviceSettingsIn->pp.FullScreen_RefreshRateInHz;
  2452.         }
  2453.         else 
  2454.         {
  2455.             UINT refreshRateMatch;
  2456.             if( pMatchOptions->eRefreshRate == DXUTMT_CLOSEST_TO_INPUT )   
  2457.             {
  2458.                 refreshRateMatch = pDeviceSettingsIn->pp.FullScreen_RefreshRateInHz;
  2459.             }
  2460.             else // if( pMatchOptions->eRefreshRate == DXUTMT_IGNORE_INPUT )   
  2461.             {
  2462.                 refreshRateMatch = adapterDesktopDisplayMode.RefreshRate;
  2463.             }
  2464.  
  2465.             bestDisplayMode.RefreshRate = 0;
  2466.  
  2467.             if( refreshRateMatch != 0 )
  2468.             {
  2469.                 int nBestRefreshRanking = 100000;
  2470.                 CGrowableArray<D3DDISPLAYMODE>* pDisplayModeList = &pBestDeviceSettingsCombo->pAdapterInfo->displayModeList;
  2471.                 for( int iDisplayMode=0; iDisplayMode<pDisplayModeList->GetSize(); iDisplayMode++ )
  2472.                 {
  2473.                     D3DDISPLAYMODE displayMode = pDisplayModeList->GetAt(iDisplayMode);                
  2474.                     if( displayMode.Format != pBestDeviceSettingsCombo->AdapterFormat || 
  2475.                         displayMode.Height != bestDisplayMode.Height ||
  2476.                         displayMode.Width != bestDisplayMode.Width )
  2477.                         continue; // Skip display modes that don't match 
  2478.  
  2479.                     // Find the delta between the current refresh rate and the optimal refresh rate 
  2480.                     int nCurRanking = abs((int)displayMode.RefreshRate - (int)refreshRateMatch);
  2481.                                         
  2482.                     if( nCurRanking < nBestRefreshRanking )
  2483.                     {
  2484.                         bestDisplayMode.RefreshRate = displayMode.RefreshRate;
  2485.                         nBestRefreshRanking = nCurRanking;
  2486.  
  2487.                         // Stop if perfect match found
  2488.                         if( nBestRefreshRanking == 0 )
  2489.                             break;
  2490.                     }
  2491.                 }
  2492.             }
  2493.         }
  2494.     }
  2495.  
  2496.     //---------------------
  2497.     // Present interval
  2498.     //---------------------
  2499.     UINT bestPresentInterval;
  2500.     if( pMatchOptions->ePresentInterval == DXUTMT_PRESERVE_INPUT )   
  2501.     {
  2502.         bestPresentInterval = pDeviceSettingsIn->pp.PresentationInterval;
  2503.     }
  2504.     else if( pMatchOptions->ePresentInterval == DXUTMT_IGNORE_INPUT )   
  2505.     {
  2506.         if( pBestDeviceSettingsCombo->Windowed )
  2507.         {
  2508.             // For windowed, the framework defaults to D3DPRESENT_INTERVAL_IMMEDIATE
  2509.             // which will wait not for the vertical retrace period to prevent tearing, 
  2510.             // but may introduce tearing
  2511.             bestPresentInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
  2512.         }
  2513.         else
  2514.         {
  2515.             // For full screen, the framework defaults to D3DPRESENT_INTERVAL_DEFAULT 
  2516.             // which will wait for the vertical retrace period to prevent tearing
  2517.             bestPresentInterval = D3DPRESENT_INTERVAL_DEFAULT;
  2518.         }
  2519.     }
  2520.     else // if( pMatchOptions->ePresentInterval == DXUTMT_CLOSEST_TO_INPUT )   
  2521.     {
  2522.         if( pBestDeviceSettingsCombo->presentIntervalList.Contains( pDeviceSettingsIn->pp.PresentationInterval ) )
  2523.         {
  2524.             bestPresentInterval = pDeviceSettingsIn->pp.PresentationInterval;
  2525.         }
  2526.         else
  2527.         {
  2528.             if( pBestDeviceSettingsCombo->Windowed )
  2529.                 bestPresentInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
  2530.             else
  2531.                 bestPresentInterval = D3DPRESENT_INTERVAL_DEFAULT;
  2532.         }
  2533.     }
  2534.  
  2535.     // Fill the device settings struct
  2536.     ZeroMemory( pValidDeviceSettings, sizeof(DXUTDeviceSettings) );
  2537.     pValidDeviceSettings->AdapterOrdinal                 = pBestDeviceSettingsCombo->AdapterOrdinal;
  2538.     pValidDeviceSettings->DeviceType                     = pBestDeviceSettingsCombo->DeviceType;
  2539.     pValidDeviceSettings->AdapterFormat                  = pBestDeviceSettingsCombo->AdapterFormat;
  2540.     pValidDeviceSettings->BehaviorFlags                  = dwBestBehaviorFlags;
  2541.     pValidDeviceSettings->pp.BackBufferWidth             = bestDisplayMode.Width;
  2542.     pValidDeviceSettings->pp.BackBufferHeight            = bestDisplayMode.Height;
  2543.     pValidDeviceSettings->pp.BackBufferFormat            = pBestDeviceSettingsCombo->BackBufferFormat;
  2544.     pValidDeviceSettings->pp.BackBufferCount             = bestBackBufferCount;
  2545.     pValidDeviceSettings->pp.MultiSampleType             = bestMultiSampleType;  
  2546.     pValidDeviceSettings->pp.MultiSampleQuality          = bestMultiSampleQuality;
  2547.     pValidDeviceSettings->pp.SwapEffect                  = bestSwapEffect;
  2548.     pValidDeviceSettings->pp.hDeviceWindow               = pBestDeviceSettingsCombo->Windowed ? DXUTGetHWNDDeviceWindowed() : DXUTGetHWNDDeviceFullScreen();
  2549.     pValidDeviceSettings->pp.Windowed                    = pBestDeviceSettingsCombo->Windowed;
  2550.     pValidDeviceSettings->pp.EnableAutoDepthStencil      = bestEnableAutoDepthStencil;  
  2551.     pValidDeviceSettings->pp.AutoDepthStencilFormat      = bestDepthStencilFormat;
  2552.     pValidDeviceSettings->pp.Flags                       = dwBestFlags;                   
  2553.     pValidDeviceSettings->pp.FullScreen_RefreshRateInHz  = bestDisplayMode.RefreshRate;
  2554.     pValidDeviceSettings->pp.PresentationInterval        = bestPresentInterval;
  2555. }
  2556.  
  2557.  
  2558. //--------------------------------------------------------------------------------------
  2559. // Internal helper function to find the closest allowed display mode to the optimal 
  2560. //--------------------------------------------------------------------------------------
  2561. HRESULT DXUTFindValidResolution( CD3DEnumDeviceSettingsCombo* pBestDeviceSettingsCombo, 
  2562.                                 D3DDISPLAYMODE displayModeIn, D3DDISPLAYMODE* pBestDisplayMode )
  2563. {
  2564.     D3DDISPLAYMODE bestDisplayMode;
  2565.     ZeroMemory( &bestDisplayMode, sizeof(D3DDISPLAYMODE) );
  2566.     
  2567.     if( pBestDeviceSettingsCombo->Windowed )
  2568.     {
  2569.         // Get the desktop resolution of the current monitor to use to keep the window
  2570.         // in a reasonable size in the desktop's 
  2571.         // This isn't the same as the current resolution from GetAdapterDisplayMode
  2572.         // since the device might be fullscreen 
  2573.         CD3DEnumeration* pd3dEnum = DXUTPrepareEnumerationObject();
  2574.         CD3DEnumAdapterInfo* pAdapterInfo = pd3dEnum->GetAdapterInfo( pBestDeviceSettingsCombo->AdapterOrdinal );                       
  2575.         DEVMODE devMode;
  2576.         ZeroMemory( &devMode, sizeof(DEVMODE) );
  2577.         devMode.dmSize = sizeof(DEVMODE);
  2578.         WCHAR strDeviceName[256];
  2579.         MultiByteToWideChar( CP_ACP, 0, pAdapterInfo->AdapterIdentifier.DeviceName, -1, strDeviceName, 256 );
  2580.         strDeviceName[255] = 0;
  2581.         EnumDisplaySettings( strDeviceName, ENUM_REGISTRY_SETTINGS, &devMode );
  2582.         UINT nMonitorWidth = devMode.dmPelsWidth;
  2583.         UINT nMonitorHeight = devMode.dmPelsHeight;
  2584.  
  2585.         // For windowed mode, just keep it something reasonable within the size 
  2586.         // of the working area of the desktop
  2587.         if( displayModeIn.Width > nMonitorWidth - 20 )
  2588.             displayModeIn.Width = nMonitorWidth - 20;
  2589.         if( displayModeIn.Height > nMonitorHeight - 100 )
  2590.             displayModeIn.Height = nMonitorHeight - 100;
  2591.  
  2592.         *pBestDisplayMode = displayModeIn;
  2593.     }
  2594.     else
  2595.     {
  2596.         int nBestRanking = 100000;
  2597.         int nCurRanking;
  2598.         CGrowableArray<D3DDISPLAYMODE>* pDisplayModeList = &pBestDeviceSettingsCombo->pAdapterInfo->displayModeList;
  2599.         for( int iDisplayMode=0; iDisplayMode<pDisplayModeList->GetSize(); iDisplayMode++ )
  2600.         {
  2601.             D3DDISPLAYMODE displayMode = pDisplayModeList->GetAt(iDisplayMode);
  2602.  
  2603.             // Skip display modes that don't match the combo's adapter format
  2604.             if( displayMode.Format != pBestDeviceSettingsCombo->AdapterFormat )
  2605.                 continue;
  2606.  
  2607.             // Find the delta between the current width/height and the optimal width/height
  2608.             nCurRanking = abs((int)displayMode.Width - (int)displayModeIn.Width) + 
  2609.                           abs((int)displayMode.Height- (int)displayModeIn.Height);
  2610.  
  2611.             if( nCurRanking < nBestRanking )
  2612.             {
  2613.                 bestDisplayMode = displayMode;
  2614.                 nBestRanking = nCurRanking;
  2615.  
  2616.                 // Stop if perfect match found
  2617.                 if( nBestRanking == 0 )
  2618.                     break;
  2619.             }
  2620.         }
  2621.  
  2622.         if( bestDisplayMode.Width == 0 )
  2623.         {
  2624.             *pBestDisplayMode = displayModeIn;
  2625.             return E_FAIL; // No valid display modes found
  2626.         }
  2627.  
  2628.         *pBestDisplayMode = bestDisplayMode;
  2629.     }
  2630.  
  2631.     return S_OK;
  2632. }
  2633.  
  2634.  
  2635. //--------------------------------------------------------------------------------------
  2636. // Internal helper function to return the adapter format from the first device settings 
  2637. // combo that matches the passed adapter ordinal, device type, backbuffer format, and windowed.  
  2638. //--------------------------------------------------------------------------------------
  2639. HRESULT DXUTFindAdapterFormat( UINT AdapterOrdinal, D3DDEVTYPE DeviceType, D3DFORMAT BackBufferFormat, 
  2640.                                BOOL Windowed, D3DFORMAT* pAdapterFormat )
  2641. {
  2642.     CD3DEnumeration* pd3dEnum = DXUTPrepareEnumerationObject();
  2643.     CD3DEnumDeviceInfo* pDeviceInfo = pd3dEnum->GetDeviceInfo( AdapterOrdinal, DeviceType );
  2644.     if( pDeviceInfo )
  2645.     {
  2646.         for( int iDeviceCombo=0; iDeviceCombo<pDeviceInfo->deviceSettingsComboList.GetSize(); iDeviceCombo++ )
  2647.         {
  2648.             CD3DEnumDeviceSettingsCombo* pDeviceSettingsCombo = pDeviceInfo->deviceSettingsComboList.GetAt(iDeviceCombo);
  2649.             if( pDeviceSettingsCombo->BackBufferFormat == BackBufferFormat &&
  2650.                 pDeviceSettingsCombo->Windowed == Windowed )
  2651.             {
  2652.                 // Return the adapter format from the first match
  2653.                 *pAdapterFormat = pDeviceSettingsCombo->AdapterFormat;
  2654.                 return S_OK;
  2655.             }
  2656.         }
  2657.     }
  2658.  
  2659.     *pAdapterFormat = BackBufferFormat;
  2660.     return E_FAIL;
  2661. }
  2662.  
  2663.  
  2664. //--------------------------------------------------------------------------------------
  2665. // Change to a Direct3D device created from the device settings or passed in.
  2666. // The framework will only reset if the device is similar to the previous device 
  2667. // otherwise it will cleanup the previous device (if there is one) and recreate the 
  2668. // scene using the app's device callbacks.
  2669. //--------------------------------------------------------------------------------------
  2670. HRESULT DXUTChangeDevice( DXUTDeviceSettings* pNewDeviceSettings, IDirect3DDevice9* pd3dDeviceFromApp, bool bForceRecreate )
  2671. {
  2672.     HRESULT hr;
  2673.     DXUTDeviceSettings* pOldDeviceSettings = GetDXUTState().GetCurrentDeviceSettings();
  2674.  
  2675.     if( DXUTGetD3DObject() == NULL )
  2676.         return S_FALSE;
  2677.  
  2678.     // Make a copy of the pNewDeviceSettings on the heap
  2679.     DXUTDeviceSettings* pNewDeviceSettingsOnHeap = new DXUTDeviceSettings;
  2680.     if( pNewDeviceSettingsOnHeap == NULL )
  2681.         return E_OUTOFMEMORY;
  2682.     memcpy( pNewDeviceSettingsOnHeap, pNewDeviceSettings, sizeof(DXUTDeviceSettings) );
  2683.     pNewDeviceSettings = pNewDeviceSettingsOnHeap;
  2684.  
  2685.     GetDXUTState().SetCurrentDeviceSettings( pNewDeviceSettings );
  2686.  
  2687.     DXUTPause( true, true );
  2688.  
  2689.     // When a WM_SIZE message is received, it calls DXUTHandlePossibleSizeChange().
  2690.     // A WM_SIZE message might be sent when adjusting the window, so tell 
  2691.     // DXUTHandlePossibleSizeChange() to ignore size changes temporarily
  2692.     GetDXUTState().SetIgnoreSizeChange( true );
  2693.  
  2694.     // Update thread safety on/off depending on Direct3D device's thread safety
  2695.     g_bThreadSafe = ((pNewDeviceSettings->BehaviorFlags & D3DCREATE_MULTITHREADED) != 0 );
  2696.  
  2697.     // Only apply the cmd line overrides if this is the first device created
  2698.     // and DXUTSetDevice() isn't used
  2699.     if( NULL == pd3dDeviceFromApp && NULL == pOldDeviceSettings )
  2700.     {
  2701.         // Updates the device settings struct based on the cmd line args.  
  2702.         // Warning: if the device doesn't support these new settings then CreateDevice() will fail.
  2703.         DXUTUpdateDeviceSettingsWithOverrides( pNewDeviceSettings );
  2704.     }
  2705.  
  2706.     // If windowed, then update the window client rect and window bounds rect
  2707.     // with the new pp.BackBufferWidth & pp.BackBufferHeight
  2708.     // The window will be resized after the device is reset/creeted
  2709.     if( pNewDeviceSettings->pp.Windowed )
  2710.     {
  2711.         // Don't allow smaller than what's used in WM_GETMINMAXINFO
  2712.         // otherwise the window size will be different than the backbuffer size
  2713.         if( pNewDeviceSettings->pp.BackBufferWidth < MIN_WINDOW_SIZE_X )
  2714.             pNewDeviceSettings->pp.BackBufferWidth = MIN_WINDOW_SIZE_X;
  2715.         if( pNewDeviceSettings->pp.BackBufferHeight < MIN_WINDOW_SIZE_Y )
  2716.             pNewDeviceSettings->pp.BackBufferHeight = MIN_WINDOW_SIZE_Y;
  2717.  
  2718.         RECT rcWindowClient = GetDXUTState().GetWindowClientRect();
  2719.         rcWindowClient.right = pNewDeviceSettings->pp.BackBufferWidth;
  2720.         rcWindowClient.bottom = pNewDeviceSettings->pp.BackBufferHeight;
  2721.         AdjustWindowRect( &rcWindowClient, GetDXUTState().GetWinStyle(), ( GetDXUTState().GetMenu() != NULL ) ? true : false );
  2722.         SetRect( &rcWindowClient, 0, 0, rcWindowClient.right - rcWindowClient.left, rcWindowClient.bottom - rcWindowClient.top );
  2723.         GetDXUTState().SetWindowClientRect( rcWindowClient );
  2724.  
  2725.         RECT rcWindowBounds = GetDXUTState().GetWindowBoundsRect();
  2726.         SetRect( &rcWindowBounds, rcWindowBounds.left, rcWindowBounds.top, rcWindowBounds.left + rcWindowClient.right, rcWindowBounds.top + rcWindowClient.bottom );
  2727.         GetDXUTState().SetWindowBoundsRect( rcWindowBounds );
  2728.     }
  2729.  
  2730.     // Enable/disable StickKeys shortcut, ToggleKeys shortcut, FilterKeys shortcut, and Windows key 
  2731.     // to prevent accidental task switching
  2732.     if( pNewDeviceSettings->pp.Windowed )
  2733.         DXUTAllowShortcutKeys( GetDXUTState().GetAllowShortcutKeysWhenWindowed() );
  2734.     else
  2735.         DXUTAllowShortcutKeys( GetDXUTState().GetAllowShortcutKeysWhenFullscreen() );
  2736.  
  2737.     // If AdapterOrdinal and DeviceType are the same, we can just do a Reset().
  2738.     // If they've changed, we need to do a complete device tear down/rebuild.
  2739.     // Also only allow a reset if pd3dDevice is the same as the current device 
  2740.     if( !bForceRecreate && 
  2741.         (pd3dDeviceFromApp == NULL || pd3dDeviceFromApp == DXUTGetD3DDevice()) && 
  2742.         pOldDeviceSettings &&
  2743.         pOldDeviceSettings->AdapterOrdinal == pNewDeviceSettings->AdapterOrdinal &&
  2744.         pOldDeviceSettings->DeviceType == pNewDeviceSettings->DeviceType &&
  2745.         pOldDeviceSettings->BehaviorFlags == pNewDeviceSettings->BehaviorFlags )
  2746.     {
  2747.         // Reset the Direct3D device 
  2748.         hr = DXUTReset3DEnvironment();
  2749.         if( FAILED(hr) )
  2750.         {
  2751.             if( D3DERR_DEVICELOST == hr )
  2752.             {
  2753.                 // The device is lost, so wait until it can be reset
  2754.                 SAFE_DELETE( pOldDeviceSettings );
  2755.                 DXUTPause( false, false );
  2756.                 GetDXUTState().SetDeviceLost( true );
  2757.                 return S_OK;
  2758.             }
  2759.             else if( DXUTERR_RESETTINGDEVICEOBJECTS == hr || 
  2760.                      DXUTERR_MEDIANOTFOUND == hr )
  2761.             {
  2762.                 SAFE_DELETE( pOldDeviceSettings );
  2763.                 DXUTDisplayErrorMessage( hr );
  2764.                 DXUTShutdown();
  2765.                 return hr;
  2766.             }
  2767.             else // DXUTERR_RESETTINGDEVICE
  2768.             {
  2769.                 // Reset failed, but the device wasn't lost so something bad happened, 
  2770.                 // so recreate the device to try to recover
  2771.                 GetDXUTState().SetCurrentDeviceSettings( pOldDeviceSettings );
  2772.                 if( FAILED( DXUTChangeDevice( pNewDeviceSettings, pd3dDeviceFromApp, true ) ) )
  2773.                 {
  2774.                     SAFE_DELETE( pOldDeviceSettings );
  2775.                     DXUTShutdown();
  2776.                     return DXUTERR_CREATINGDEVICE;
  2777.                 }
  2778.                 else
  2779.                 {
  2780.                     SAFE_DELETE( pOldDeviceSettings );
  2781.                     return S_OK;
  2782.                 }
  2783.             }
  2784.         }
  2785.     }
  2786.     else
  2787.     {
  2788.         // Recreate the Direct3D device 
  2789.         if( pOldDeviceSettings )
  2790.         {
  2791.             // The adapter and device type don't match so 
  2792.             // cleanup and create the 3D device again
  2793.             DXUTCleanup3DEnvironment( false );
  2794.         }
  2795.  
  2796.         IDirect3DDevice9* pd3dDevice = NULL;
  2797.  
  2798.         // Only create a Direct3D device if one hasn't been supplied by the app
  2799.         if( pd3dDeviceFromApp == NULL )
  2800.         {
  2801.             if( NULL == pOldDeviceSettings && 
  2802.                 pNewDeviceSettings->DeviceType == D3DDEVTYPE_REF && 
  2803.                 !GetDXUTState().GetOverrideForceREF() )
  2804.             {
  2805.                 DXUTDisplayErrorMessage( DXUTERR_SWITCHEDTOREF );
  2806.             }
  2807.  
  2808.             // Try to create the device with the chosen settings
  2809.             IDirect3D9* pD3D = DXUTGetD3DObject();
  2810.             hr = pD3D->CreateDevice( pNewDeviceSettings->AdapterOrdinal, pNewDeviceSettings->DeviceType, 
  2811.                                     DXUTGetHWNDFocus(), pNewDeviceSettings->BehaviorFlags,
  2812.                                     &pNewDeviceSettings->pp, &pd3dDevice );
  2813.             if( FAILED(hr) )
  2814.             {
  2815.                 DXUTPause( false, false );
  2816.                 DXUTDisplayErrorMessage( DXUTERR_CREATINGDEVICE );
  2817.                 return DXUT_ERR( L"CreateDevice", hr );
  2818.             }
  2819.         }
  2820.         else
  2821.         {
  2822.             pd3dDeviceFromApp->AddRef();
  2823.             pd3dDevice = pd3dDeviceFromApp;
  2824.         }
  2825.  
  2826.         GetDXUTState().SetD3DDevice( pd3dDevice );
  2827.  
  2828.         // Now that the device is created, update the window and misc settings and
  2829.         // call the app's DeviceCreated and DeviceReset callbacks.
  2830.         hr = DXUTInitialize3DEnvironment();
  2831.         if( FAILED(hr) )
  2832.         {
  2833.             DXUTDisplayErrorMessage( hr );
  2834.             DXUTPause( false, false );
  2835.             return hr;
  2836.         }
  2837.  
  2838.         // Update the device stats text
  2839.         CD3DEnumeration* pd3dEnum = DXUTPrepareEnumerationObject();
  2840.         CD3DEnumAdapterInfo* pAdapterInfo = pd3dEnum->GetAdapterInfo( pNewDeviceSettings->AdapterOrdinal );
  2841.         DXUTUpdateDeviceStats( pNewDeviceSettings->DeviceType, 
  2842.                             pNewDeviceSettings->BehaviorFlags, 
  2843.                             &pAdapterInfo->AdapterIdentifier );
  2844.     }
  2845.  
  2846.     SAFE_DELETE( pOldDeviceSettings );
  2847.  
  2848.     IDirect3D9* pD3D = DXUTGetD3DObject();
  2849.     HMONITOR hAdapterMonitor = pD3D->GetAdapterMonitor( pNewDeviceSettings->AdapterOrdinal );
  2850.     GetDXUTState().SetAdapterMonitor( hAdapterMonitor );
  2851.  
  2852.     // When moving from full screen to windowed mode, it is important to
  2853.     // adjust the window size after resetting the device rather than
  2854.     // beforehand to ensure that you get the window size you want.  For
  2855.     // example, when switching from 640x480 full screen to windowed with
  2856.     // a 1000x600 window on a 1024x768 desktop, it is impossible to set
  2857.     // the window size to 1000x600 until after the display mode has
  2858.     // changed to 1024x768, because windows cannot be larger than the
  2859.     // desktop.
  2860.     if( pNewDeviceSettings->pp.Windowed )
  2861.     {
  2862.         RECT rcWindowBounds = GetDXUTState().GetWindowBoundsRect();
  2863.  
  2864.         // Resize the window
  2865.         POINT ptClient = { rcWindowBounds.left, rcWindowBounds.top };
  2866.         ScreenToClient( GetParent( DXUTGetHWNDDeviceWindowed() ), &ptClient );
  2867.         SetWindowPos( DXUTGetHWND(), HWND_NOTOPMOST,
  2868.                       ptClient.x, ptClient.y,
  2869.                       ( rcWindowBounds.right - rcWindowBounds.left ),
  2870.                       ( rcWindowBounds.bottom - rcWindowBounds.top ),
  2871.                       0 );
  2872.  
  2873.         // Update the cache of the window style
  2874.         GetDXUTState().SetWinStyle( GetDXUTState().GetWinStyle() | WS_VISIBLE );
  2875.  
  2876.         // Check to see if the window changed monitors
  2877.         MONITORINFO miAdapter;
  2878.         miAdapter.cbSize = sizeof(MONITORINFO);
  2879.         GetMonitorInfo( hAdapterMonitor, &miAdapter );
  2880.         int nMonitorWidth = miAdapter.rcWork.right - miAdapter.rcWork.left;
  2881.         int nMonitorHeight = miAdapter.rcWork.bottom - miAdapter.rcWork.top;
  2882.  
  2883.         HMONITOR hWindowMonitor = MonitorFromWindow( DXUTGetHWND(), MONITOR_DEFAULTTOPRIMARY );
  2884.         MONITORINFO miWindow;
  2885.         miWindow.cbSize = sizeof(MONITORINFO);
  2886.         GetMonitorInfo( hWindowMonitor, &miWindow );
  2887.  
  2888.         // Dragging the window does not cause a monitor change here, 
  2889.         // but changing the adapter does
  2890.         bool bMonitorChanged = ( hAdapterMonitor != hWindowMonitor );
  2891.  
  2892.         rcWindowBounds = GetDXUTState().GetWindowBoundsRect();
  2893.         int nWindowOffsetX = rcWindowBounds.left - miWindow.rcMonitor.left;
  2894.         int nWindowOffsetY = rcWindowBounds.top - miWindow.rcMonitor.top;
  2895.         int nWindowWidth = rcWindowBounds.right - rcWindowBounds.left;
  2896.         int nWindowHeight = rcWindowBounds.bottom - rcWindowBounds.top;
  2897.  
  2898.         if( GetDXUTState().GetWindowCreatedWithDefaultPositions() )
  2899.         {
  2900.             // Since the window was created with a default window position
  2901.             // center it in the work area if its outside the monitor's work area
  2902.  
  2903.             // Only do this the first time.
  2904.             GetDXUTState().SetWindowCreatedWithDefaultPositions( false );
  2905.  
  2906.             // Center window if the bottom or right of the window is outside the monitor's work area
  2907.             if( miAdapter.rcWork.left + nWindowOffsetX + nWindowWidth > miAdapter.rcWork.right )
  2908.                 nWindowOffsetX = (nMonitorWidth - nWindowWidth) / 2;
  2909.             if( miAdapter.rcWork.top + nWindowOffsetY + nWindowHeight > miAdapter.rcWork.bottom )
  2910.                 nWindowOffsetY = (nMonitorHeight - nWindowHeight) / 2;
  2911.         }        
  2912.  
  2913.         if( bMonitorChanged )
  2914.         {
  2915.             // Make sure that when changing between monitors of different resolutions, the window isn't 
  2916.             // positioned outside the monitor's client rect
  2917.             if( nWindowOffsetX + nWindowWidth > nMonitorWidth )
  2918.                 nWindowOffsetX = nMonitorWidth - nWindowWidth;
  2919.             if( nWindowOffsetY + nWindowHeight > nMonitorHeight )
  2920.                 nWindowOffsetY = nMonitorHeight - nWindowHeight;
  2921.         }
  2922.  
  2923.         // Move & show the window 
  2924.         ptClient.x = miAdapter.rcMonitor.left + nWindowOffsetX;
  2925.         ptClient.y = miAdapter.rcMonitor.top + nWindowOffsetY;
  2926.         ScreenToClient( GetParent( DXUTGetHWND() ), &ptClient );
  2927.         SetWindowPos( DXUTGetHWND(), HWND_NOTOPMOST, 
  2928.                       ptClient.x, 
  2929.                       ptClient.y, 
  2930.                       0, 0, SWP_NOSIZE|SWP_SHOWWINDOW );
  2931.  
  2932.         // Save the window position & size 
  2933.         RECT rcWindowClient;
  2934.         GetClientRect( DXUTGetHWNDDeviceWindowed(), &rcWindowClient );
  2935.         GetDXUTState().SetWindowClientRect( rcWindowClient );
  2936.         GetWindowRect( DXUTGetHWNDDeviceWindowed(), &rcWindowBounds );
  2937.         GetDXUTState().SetWindowBoundsRect( rcWindowBounds );
  2938.     }
  2939.     else
  2940.     {
  2941.         RECT rcWindowClient;
  2942.         SetRect( &rcWindowClient, 0, 0, pNewDeviceSettings->pp.BackBufferWidth,pNewDeviceSettings->pp.BackBufferHeight );
  2943.         GetDXUTState().SetFullScreenClientRect( rcWindowClient );  
  2944.     }
  2945.  
  2946.     GetDXUTState().SetIgnoreSizeChange( false );
  2947.     DXUTPause( false, false );
  2948.     GetDXUTState().SetDeviceCreated( true );
  2949.  
  2950.     return S_OK;
  2951. }
  2952.  
  2953.  
  2954. //--------------------------------------------------------------------------------------
  2955. // Low level keyboard hook to disable Windows key to prevent accidental task switching.  
  2956. //--------------------------------------------------------------------------------------
  2957. LRESULT CALLBACK LowLevelKeyboardProc( int nCode, WPARAM wParam, LPARAM lParam )
  2958. {
  2959.     if (nCode < 0 || nCode != HC_ACTION)  // do not process message 
  2960.         return CallNextHookEx( GetDXUTState().GetKeyboardHook(), nCode, wParam, lParam); 
  2961.  
  2962.     bool bEatKeystroke = false;
  2963.     KBDLLHOOKSTRUCT* p = (KBDLLHOOKSTRUCT*)lParam;
  2964.     switch (wParam) 
  2965.     {
  2966.         case WM_KEYDOWN:  
  2967.         case WM_KEYUP:    
  2968.         {
  2969.             bEatKeystroke = ( !GetDXUTState().GetAllowShortcutKeys() && 
  2970.                             (p->vkCode == VK_LWIN || p->vkCode == VK_RWIN) );
  2971.             break;
  2972.         }
  2973.     }
  2974.  
  2975.     if( bEatKeystroke )
  2976.         return 1;
  2977.     else
  2978.         return CallNextHookEx( GetDXUTState().GetKeyboardHook(), nCode, wParam, lParam );
  2979. }
  2980.  
  2981.  
  2982.  
  2983. //--------------------------------------------------------------------------------------
  2984. // Controls how DXUT behaves when fullscreen and windowed mode with regard to 
  2985. // shortcut keys (Windows keys, StickyKeys shortcut, ToggleKeys shortcut, FilterKeys shortcut) 
  2986. //--------------------------------------------------------------------------------------
  2987. void DXUTSetShortcutKeySettings( bool bAllowWhenFullscreen, bool bAllowWhenWindowed )
  2988. {
  2989.     GetDXUTState().SetAllowShortcutKeysWhenWindowed( bAllowWhenWindowed );
  2990.     GetDXUTState().SetAllowShortcutKeysWhenFullscreen( bAllowWhenFullscreen );
  2991.  
  2992.     // DXUTInit() records initial accessibility states so don't change them until then
  2993.     if( GetDXUTState().GetDXUTInited() )
  2994.     {
  2995.         if( DXUTIsWindowed() )
  2996.             DXUTAllowShortcutKeys( GetDXUTState().GetAllowShortcutKeysWhenWindowed() );
  2997.         else
  2998.             DXUTAllowShortcutKeys( GetDXUTState().GetAllowShortcutKeysWhenFullscreen() );
  2999.     }
  3000. }
  3001.  
  3002.  
  3003. //--------------------------------------------------------------------------------------
  3004. // Enables/disables Windows keys, and disables or restores the StickyKeys/ToggleKeys/FilterKeys 
  3005. // shortcut to help prevent accidental task switching
  3006. //--------------------------------------------------------------------------------------
  3007. void DXUTAllowShortcutKeys( bool bAllowKeys )
  3008. {
  3009.     GetDXUTState().SetAllowShortcutKeys( bAllowKeys );
  3010.  
  3011.     if( bAllowKeys )
  3012.     {
  3013.         // Restore StickyKeys/etc to original state and enable Windows key      
  3014.         STICKYKEYS sk = GetDXUTState().GetStartupStickyKeys();
  3015.         TOGGLEKEYS tk = GetDXUTState().GetStartupToggleKeys();
  3016.         FILTERKEYS fk = GetDXUTState().GetStartupFilterKeys();
  3017.         
  3018.         SystemParametersInfo(SPI_SETSTICKYKEYS, sizeof(STICKYKEYS), &sk, 0);
  3019.         SystemParametersInfo(SPI_SETTOGGLEKEYS, sizeof(TOGGLEKEYS), &tk, 0);
  3020.         SystemParametersInfo(SPI_SETFILTERKEYS, sizeof(FILTERKEYS), &fk, 0);
  3021.     }
  3022.     else
  3023.     {
  3024.         // Set low level keyboard hook if haven't already
  3025.         if( GetDXUTState().GetKeyboardHook() == NULL )
  3026.         {
  3027.             // Set the low-level hook procedure.  Only works on Windows 2000 and above
  3028.             OSVERSIONINFO OSVersionInfo;
  3029.             OSVersionInfo.dwOSVersionInfoSize = sizeof(OSVersionInfo);
  3030.             GetVersionEx(&OSVersionInfo);
  3031.             if( OSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT && OSVersionInfo.dwMajorVersion > 4 )
  3032.             {
  3033.                 HHOOK hKeyboardHook = SetWindowsHookEx( WH_KEYBOARD_LL, LowLevelKeyboardProc, GetModuleHandle(NULL), 0 );
  3034.                 GetDXUTState().SetKeyboardHook( hKeyboardHook );
  3035.             }
  3036.         }
  3037.  
  3038.         // Disable StickyKeys/etc shortcuts but if the accessibility feature is on, 
  3039.         // then leave the settings alone as its probably being usefully used
  3040.  
  3041.         STICKYKEYS skOff = GetDXUTState().GetStartupStickyKeys();
  3042.         if( (skOff.dwFlags & SKF_STICKYKEYSON) == 0 )
  3043.         {
  3044.             // Disable the hotkey and the confirmation
  3045.             skOff.dwFlags &= ~SKF_HOTKEYACTIVE;
  3046.             skOff.dwFlags &= ~SKF_CONFIRMHOTKEY;
  3047.  
  3048.             SystemParametersInfo(SPI_SETSTICKYKEYS, sizeof(STICKYKEYS), &skOff, 0);
  3049.         }
  3050.  
  3051.         TOGGLEKEYS tkOff = GetDXUTState().GetStartupToggleKeys();
  3052.         if( (tkOff.dwFlags & TKF_TOGGLEKEYSON) == 0 )
  3053.         {
  3054.             // Disable the hotkey and the confirmation
  3055.             tkOff.dwFlags &= ~TKF_HOTKEYACTIVE;
  3056.             tkOff.dwFlags &= ~TKF_CONFIRMHOTKEY;
  3057.  
  3058.             SystemParametersInfo(SPI_SETTOGGLEKEYS, sizeof(TOGGLEKEYS), &tkOff, 0);
  3059.         }
  3060.  
  3061.         FILTERKEYS fkOff = GetDXUTState().GetStartupFilterKeys();
  3062.         if( (fkOff.dwFlags & FKF_FILTERKEYSON) == 0 )
  3063.         {
  3064.             // Disable the hotkey and the confirmation
  3065.             fkOff.dwFlags &= ~FKF_HOTKEYACTIVE;
  3066.             fkOff.dwFlags &= ~FKF_CONFIRMHOTKEY;
  3067.  
  3068.             SystemParametersInfo(SPI_SETFILTERKEYS, sizeof(FILTERKEYS), &fkOff, 0);
  3069.         }
  3070.     }
  3071. }
  3072.  
  3073.  
  3074. //--------------------------------------------------------------------------------------
  3075. // Updates the device settings struct based on the cmd line args.  
  3076. //--------------------------------------------------------------------------------------
  3077. void DXUTUpdateDeviceSettingsWithOverrides( DXUTDeviceSettings* pDeviceSettings )
  3078. {
  3079.     if( GetDXUTState().GetOverrideAdapterOrdinal() != -1 )
  3080.         pDeviceSettings->AdapterOrdinal = GetDXUTState().GetOverrideAdapterOrdinal();
  3081.  
  3082.     if( GetDXUTState().GetOverrideFullScreen() )
  3083.         pDeviceSettings->pp.Windowed = false;
  3084.     if( GetDXUTState().GetOverrideWindowed() )
  3085.         pDeviceSettings->pp.Windowed = true;
  3086.  
  3087.     if( GetDXUTState().GetOverrideForceREF() )
  3088.         pDeviceSettings->DeviceType = D3DDEVTYPE_REF;
  3089.     else if( GetDXUTState().GetOverrideForceHAL() )
  3090.         pDeviceSettings->DeviceType = D3DDEVTYPE_HAL;
  3091.  
  3092.     if( GetDXUTState().GetOverrideWidth() != 0 )
  3093.         pDeviceSettings->pp.BackBufferWidth = GetDXUTState().GetOverrideWidth();
  3094.     if( GetDXUTState().GetOverrideHeight() != 0 )
  3095.         pDeviceSettings->pp.BackBufferHeight = GetDXUTState().GetOverrideHeight();
  3096.  
  3097.     if( GetDXUTState().GetOverrideForcePureHWVP() )
  3098.     {
  3099.         pDeviceSettings->BehaviorFlags &= ~D3DCREATE_SOFTWARE_VERTEXPROCESSING;
  3100.         pDeviceSettings->BehaviorFlags |= D3DCREATE_HARDWARE_VERTEXPROCESSING;
  3101.         pDeviceSettings->BehaviorFlags |= D3DCREATE_PUREDEVICE;
  3102.     }
  3103.     else if( GetDXUTState().GetOverrideForceHWVP() )
  3104.     {
  3105.         pDeviceSettings->BehaviorFlags &= ~D3DCREATE_SOFTWARE_VERTEXPROCESSING;
  3106.         pDeviceSettings->BehaviorFlags &= ~D3DCREATE_PUREDEVICE;
  3107.         pDeviceSettings->BehaviorFlags |= D3DCREATE_HARDWARE_VERTEXPROCESSING;
  3108.     }
  3109.     else if( GetDXUTState().GetOverrideForceSWVP() )
  3110.     {
  3111.         pDeviceSettings->BehaviorFlags &= ~D3DCREATE_HARDWARE_VERTEXPROCESSING;
  3112.         pDeviceSettings->BehaviorFlags &= ~D3DCREATE_PUREDEVICE;
  3113.         pDeviceSettings->BehaviorFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
  3114.     }
  3115. }
  3116.  
  3117.  
  3118. //--------------------------------------------------------------------------------------
  3119. // Initializes the 3D environment by:
  3120. //       - Adjusts the window size, style, and menu 
  3121. //       - Stores the back buffer description
  3122. //       - Sets up the full screen Direct3D cursor if requested
  3123. //       - Calls the device created callback
  3124. //       - Calls the device reset callback
  3125. //       - If both callbacks succeed it unpauses the app 
  3126. //--------------------------------------------------------------------------------------
  3127. HRESULT DXUTInitialize3DEnvironment()
  3128. {
  3129.     HRESULT hr = S_OK;
  3130.  
  3131.     IDirect3DDevice9* pd3dDevice = DXUTGetD3DDevice();
  3132.     assert( pd3dDevice != NULL );
  3133.  
  3134.     GetDXUTState().SetDeviceObjectsCreated( false );
  3135.     GetDXUTState().SetDeviceObjectsReset( false );
  3136.  
  3137.     // Prepare the window for a possible change between windowed mode 
  3138.     // and full screen mode by adjusting the window style and its menu.
  3139.     DXUTAdjustWindowStyle( DXUTGetHWND(), DXUTIsWindowed() );
  3140.  
  3141.     // Prepare the device with cursor info and 
  3142.     // store backbuffer desc and caps from the device
  3143.     DXUTPrepareDevice( pd3dDevice );
  3144.  
  3145.     // If the settings dialog exists, then call OnCreatedDevice() & OnResetDevice() on it.
  3146.     CD3DSettingsDlg* pD3DSettingsDlg = GetDXUTState().GetD3DSettingsDlg();
  3147.     if( pD3DSettingsDlg )
  3148.     {
  3149.         hr = pD3DSettingsDlg->OnCreateDevice( pd3dDevice );
  3150.         if( FAILED(hr) )
  3151.             return DXUT_ERR( L"OnCreateDevice", DXUTERR_CREATINGDEVICEOBJECTS );
  3152.  
  3153.         hr = pD3DSettingsDlg->OnResetDevice();
  3154.         if( FAILED(hr) )
  3155.             return DXUT_ERR( L"OnCreateDevice", DXUTERR_CREATINGDEVICEOBJECTS );
  3156.     }
  3157.  
  3158.     // Call the GUI resource device created function
  3159.     hr = DXUTGetGlobalDialogResourceManager()->OnCreateDevice( pd3dDevice );
  3160.     if( FAILED(hr) )
  3161.     {
  3162.         if( hr == DXUTERR_MEDIANOTFOUND )
  3163.             return DXUT_ERR( L"OnCreateDevice", DXUTERR_MEDIANOTFOUND );
  3164.         else
  3165.             return DXUT_ERR( L"OnCreateDevice", DXUTERR_CREATINGDEVICEOBJECTS );
  3166.     }
  3167.  
  3168.     // Call the resource cache created function
  3169.     hr = DXUTGetGlobalResourceCache().OnCreateDevice( pd3dDevice );
  3170.     if( FAILED(hr) )
  3171.     {
  3172.         if( hr == DXUTERR_MEDIANOTFOUND )
  3173.             return DXUT_ERR( L"OnCreateDevice", DXUTERR_MEDIANOTFOUND );
  3174.         else
  3175.             return DXUT_ERR( L"OnCreateDevice", DXUTERR_CREATINGDEVICEOBJECTS );
  3176.     }
  3177.  
  3178.     // Call the app's device created callback if set
  3179.     const D3DSURFACE_DESC* pbackBufferSurfaceDesc = DXUTGetBackBufferSurfaceDesc();
  3180.     GetDXUTState().SetInsideDeviceCallback( true );
  3181.     LPDXUTCALLBACKDEVICECREATED pCallbackDeviceCreated = GetDXUTState().GetDeviceCreatedFunc();
  3182.     hr = S_OK;
  3183.     if( pCallbackDeviceCreated != NULL )
  3184.         hr = pCallbackDeviceCreated( pd3dDevice, pbackBufferSurfaceDesc );
  3185.     GetDXUTState().SetInsideDeviceCallback( false );
  3186.     if( FAILED(hr) )  
  3187.     {
  3188.         // Cleanup upon failure
  3189.         DXUTCleanup3DEnvironment();
  3190.  
  3191.         DXUT_ERR( L"DeviceCreated callback", hr );        
  3192.         if( hr == DXUTERR_MEDIANOTFOUND )
  3193.             return DXUT_ERR( L"DeviceCreatedCallback", DXUTERR_MEDIANOTFOUND );
  3194.         else
  3195.             return DXUT_ERR( L"DeviceCreatedCallback", DXUTERR_CREATINGDEVICEOBJECTS );
  3196.     }
  3197.     else
  3198.     {
  3199.         // Call the GUI resource device reset function
  3200.         hr = DXUTGetGlobalDialogResourceManager()->OnResetDevice();
  3201.         if( FAILED(hr) )
  3202.             return DXUT_ERR( L"OnResetDevice", DXUTERR_RESETTINGDEVICEOBJECTS );
  3203.  
  3204.         // Call the resource cache device reset function
  3205.         hr = DXUTGetGlobalResourceCache().OnResetDevice( pd3dDevice );
  3206.         if( FAILED(hr) )
  3207.             return DXUT_ERR( L"OnResetDevice", DXUTERR_RESETTINGDEVICEOBJECTS );
  3208.  
  3209.         // Call the app's device reset callback if set
  3210.         GetDXUTState().SetDeviceObjectsCreated( true );
  3211.         GetDXUTState().SetInsideDeviceCallback( true );
  3212.         LPDXUTCALLBACKDEVICERESET pCallbackDeviceReset = GetDXUTState().GetDeviceResetFunc();
  3213.         hr = S_OK;
  3214.         if( pCallbackDeviceReset != NULL )
  3215.             hr = pCallbackDeviceReset( pd3dDevice, pbackBufferSurfaceDesc );
  3216.         GetDXUTState().SetInsideDeviceCallback( false );
  3217.         if( FAILED(hr) )
  3218.         {
  3219.             DXUT_ERR( L"DeviceReset callback", hr );
  3220.             if( hr == DXUTERR_MEDIANOTFOUND )
  3221.                 return DXUTERR_MEDIANOTFOUND;
  3222.             else
  3223.                 return DXUTERR_RESETTINGDEVICEOBJECTS;
  3224.         }
  3225.         else
  3226.         {
  3227.             GetDXUTState().SetDeviceObjectsReset( true );
  3228.             return S_OK;
  3229.         }
  3230.     }
  3231. }
  3232.  
  3233.  
  3234. //--------------------------------------------------------------------------------------
  3235. // Resets the 3D environment by:
  3236. //      - Calls the device lost callback 
  3237. //      - Resets the device
  3238. //      - Stores the back buffer description
  3239. //      - Sets up the full screen Direct3D cursor if requested
  3240. //      - Calls the device reset callback 
  3241. //--------------------------------------------------------------------------------------
  3242. HRESULT DXUTReset3DEnvironment()
  3243. {
  3244.     HRESULT hr;
  3245.  
  3246.     IDirect3DDevice9* pd3dDevice = DXUTGetD3DDevice();
  3247.     assert( pd3dDevice != NULL );
  3248.  
  3249.     CD3DSettingsDlg* pD3DSettingsDlg = GetDXUTState().GetD3DSettingsDlg();
  3250.     if( pD3DSettingsDlg )
  3251.         pD3DSettingsDlg->OnLostDevice();
  3252.  
  3253.     // Release all vidmem objects
  3254.     if( GetDXUTState().GetDeviceObjectsReset() )
  3255.     {
  3256.         GetDXUTState().SetInsideDeviceCallback( true );
  3257.  
  3258.         DXUTGetGlobalDialogResourceManager()->OnLostDevice();
  3259.         DXUTGetGlobalResourceCache().OnLostDevice();
  3260.  
  3261.         LPDXUTCALLBACKDEVICELOST pCallbackDeviceLost = GetDXUTState().GetDeviceLostFunc();
  3262.         if( pCallbackDeviceLost != NULL )
  3263.             pCallbackDeviceLost();
  3264.         GetDXUTState().SetDeviceObjectsReset( false );
  3265.         GetDXUTState().SetInsideDeviceCallback( false );
  3266.     }
  3267.  
  3268.     // Prepare the window for a possible change between windowed mode 
  3269.     // and full screen mode by adjusting the window style and its menu.
  3270.     DXUTAdjustWindowStyle( DXUTGetHWND(), DXUTIsWindowed() );
  3271.  
  3272.     // Reset the device
  3273.     DXUTDeviceSettings* pDeviceSettings = GetDXUTState().GetCurrentDeviceSettings();
  3274.     hr = pd3dDevice->Reset( &pDeviceSettings->pp );
  3275.     if( FAILED(hr) )  
  3276.     {
  3277.         if( hr == D3DERR_DEVICELOST )
  3278.             return D3DERR_DEVICELOST; // Reset could legitimately fail if the device is lost
  3279.         else
  3280.             return DXUT_ERR( L"Reset", DXUTERR_RESETTINGDEVICE );
  3281.     }
  3282.  
  3283.     // Prepare the device with cursor info and 
  3284.     // store backbuffer desc and caps from the device
  3285.     DXUTPrepareDevice( pd3dDevice );
  3286.  
  3287.     // If the settings dialog exists call its OnResetDevice() 
  3288.     if( pD3DSettingsDlg )
  3289.     {
  3290.         hr = pD3DSettingsDlg->OnResetDevice();
  3291.         if( FAILED(hr) )
  3292.             return DXUT_ERR( L"OnResetDevice", DXUTERR_RESETTINGDEVICEOBJECTS );
  3293.     }
  3294.  
  3295.     hr = DXUTGetGlobalDialogResourceManager()->OnResetDevice();
  3296.     if( FAILED(hr) )
  3297.         return DXUT_ERR( L"OnResetDevice", DXUTERR_RESETTINGDEVICEOBJECTS );
  3298.  
  3299.     hr = DXUTGetGlobalResourceCache().OnResetDevice( pd3dDevice );
  3300.     if( FAILED(hr) )
  3301.         return DXUT_ERR( L"OnResetDevice", DXUTERR_RESETTINGDEVICEOBJECTS );
  3302.  
  3303.     // Initialize the app's device-dependent objects
  3304.     GetDXUTState().SetInsideDeviceCallback( true );
  3305.     const D3DSURFACE_DESC* pbackBufferSurfaceDesc = DXUTGetBackBufferSurfaceDesc();
  3306.     LPDXUTCALLBACKDEVICERESET pCallbackDeviceReset = GetDXUTState().GetDeviceResetFunc();
  3307.     hr = S_OK;
  3308.     if( pCallbackDeviceReset != NULL )
  3309.         hr = pCallbackDeviceReset( pd3dDevice, pbackBufferSurfaceDesc );
  3310.     GetDXUTState().SetInsideDeviceCallback( false );
  3311.     if( FAILED(hr) )
  3312.     {
  3313.         DXUT_ERR( L"DeviceResetCallback", hr );
  3314.         if( hr != DXUTERR_MEDIANOTFOUND )
  3315.             hr = DXUTERR_RESETTINGDEVICEOBJECTS;
  3316.  
  3317.         DXUTGetGlobalDialogResourceManager()->OnLostDevice();
  3318.         DXUTGetGlobalResourceCache().OnLostDevice();
  3319.         
  3320.         LPDXUTCALLBACKDEVICELOST pCallbackDeviceLost = GetDXUTState().GetDeviceLostFunc();
  3321.         if( pCallbackDeviceLost != NULL )
  3322.             pCallbackDeviceLost();
  3323.     }
  3324.     else
  3325.     {
  3326.         // Success
  3327.         GetDXUTState().SetDeviceObjectsReset( true );
  3328.     }
  3329.  
  3330.     return hr;
  3331. }
  3332.  
  3333.  
  3334. //--------------------------------------------------------------------------------------
  3335. // Prepares a new or resetting device by with cursor info and 
  3336. // store backbuffer desc and caps from the device
  3337. //--------------------------------------------------------------------------------------
  3338. void DXUTPrepareDevice( IDirect3DDevice9* pd3dDevice )
  3339. {
  3340.     HRESULT hr;
  3341.  
  3342.     // Update the device stats text
  3343.     DXUTUpdateStaticFrameStats();
  3344.  
  3345.     // Store render target surface desc
  3346.     IDirect3DSurface9* pBackBuffer;
  3347.     hr = pd3dDevice->GetBackBuffer( 0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer );
  3348.     D3DSURFACE_DESC* pbackBufferSurfaceDesc = GetDXUTState().GetBackBufferSurfaceDesc();
  3349.     ZeroMemory( pbackBufferSurfaceDesc, sizeof(D3DSURFACE_DESC) );
  3350.     if( SUCCEEDED(hr) )
  3351.     {
  3352.         pBackBuffer->GetDesc( pbackBufferSurfaceDesc );
  3353.         SAFE_RELEASE( pBackBuffer );
  3354.     }
  3355.  
  3356.     // Update GetDXUTState()'s copy of D3D caps 
  3357.     D3DCAPS9* pd3dCaps = GetDXUTState().GetCaps();
  3358.     pd3dDevice->GetDeviceCaps( pd3dCaps );
  3359.  
  3360.     // Set up the full screen cursor
  3361.     if( GetDXUTState().GetShowCursorWhenFullScreen() && !DXUTIsWindowed() )
  3362.     {
  3363.         HCURSOR hCursor;
  3364. #ifdef _WIN64
  3365.         hCursor = (HCURSOR)GetClassLongPtr( DXUTGetHWND(), GCLP_HCURSOR );
  3366. #else
  3367.         hCursor = (HCURSOR)ULongToHandle( GetClassLong( DXUTGetHWND(), GCL_HCURSOR ) );
  3368. #endif
  3369.         DXUTSetDeviceCursor( pd3dDevice, hCursor, false );
  3370.         pd3dDevice->ShowCursor( true );
  3371.     }
  3372.  
  3373.     // Confine cursor to full screen window
  3374.     if( GetDXUTState().GetClipCursorWhenFullScreen() )
  3375.     {
  3376.         if( !DXUTIsWindowed() )
  3377.         {
  3378.             RECT rcWindow;
  3379.             GetWindowRect( DXUTGetHWND(), &rcWindow );
  3380.             ClipCursor( &rcWindow );
  3381.         }
  3382.         else
  3383.         {
  3384.             ClipCursor( NULL );
  3385.         }
  3386.     }
  3387. }
  3388.  
  3389.  
  3390. //--------------------------------------------------------------------------------------
  3391. // Pauses time or rendering.  Keeps a ref count so pausing can be layered
  3392. //--------------------------------------------------------------------------------------
  3393. void DXUTPause( bool bPauseTime, bool bPauseRendering )
  3394. {
  3395.     int nPauseTimeCount = GetDXUTState().GetPauseTimeCount();
  3396.     nPauseTimeCount += ( bPauseTime ? +1 : -1 );
  3397.     if( nPauseTimeCount < 0 )
  3398.         nPauseTimeCount = 0;
  3399.     GetDXUTState().SetPauseTimeCount( nPauseTimeCount );
  3400.  
  3401.     int nPauseRenderingCount = GetDXUTState().GetPauseRenderingCount();
  3402.     nPauseRenderingCount += ( bPauseRendering ? +1 : -1 );
  3403.     if( nPauseRenderingCount < 0 )
  3404.         nPauseRenderingCount = 0;
  3405.     GetDXUTState().SetPauseRenderingCount( nPauseRenderingCount );
  3406.  
  3407.     if( nPauseTimeCount > 0 )
  3408.     {
  3409.         // Stop the scene from animating
  3410.         DXUTGetGlobalTimer()->Stop();
  3411.     }
  3412.     else
  3413.     {
  3414.         // Restart the timer
  3415.         DXUTGetGlobalTimer()->Start();
  3416.     }
  3417.  
  3418.     GetDXUTState().SetRenderingPaused( nPauseRenderingCount > 0 );
  3419.     GetDXUTState().SetTimePaused( nPauseTimeCount > 0 );
  3420. }
  3421.  
  3422.  
  3423. //--------------------------------------------------------------------------------------
  3424. // Checks if the window client rect has changed and if it has, then reset the device
  3425. //--------------------------------------------------------------------------------------
  3426. void DXUTHandlePossibleSizeChange()
  3427. {
  3428.     if( !GetDXUTState().GetDeviceCreated() || GetDXUTState().GetIgnoreSizeChange() )
  3429.         return;
  3430.  
  3431.     DXUTDeviceSettings* pDeviceSettings = GetDXUTState().GetCurrentDeviceSettings();
  3432.     if( false == pDeviceSettings->pp.Windowed )
  3433.         return;
  3434.  
  3435.     HRESULT hr = S_OK;
  3436.     RECT rcClientOld = GetDXUTState().GetWindowClientRect();
  3437.  
  3438.     // Update window properties
  3439.     RECT rcWindowClient;
  3440.     GetClientRect( DXUTGetHWNDDeviceWindowed(), &rcWindowClient );
  3441.     GetDXUTState().SetWindowClientRect( rcWindowClient );
  3442.  
  3443.     RECT rcWindowBounds;
  3444.     GetWindowRect( DXUTGetHWNDDeviceWindowed(), &rcWindowBounds );
  3445.     GetDXUTState().SetWindowBoundsRect( rcWindowBounds );
  3446.  
  3447.     // Check if the window client rect has changed
  3448.     if( rcClientOld.right - rcClientOld.left != rcWindowClient.right - rcWindowClient.left ||
  3449.         rcClientOld.bottom - rcClientOld.top != rcWindowClient.bottom - rcWindowClient.top )
  3450.     {
  3451.         // A new window size will require a new backbuffer
  3452.         // size, so the 3D structures must be changed accordingly.
  3453.         DXUTPause( true, true );
  3454.  
  3455.         pDeviceSettings = GetDXUTState().GetCurrentDeviceSettings();
  3456.         pDeviceSettings->pp.BackBufferWidth  = rcWindowClient.right - rcWindowClient.left;
  3457.         pDeviceSettings->pp.BackBufferHeight = rcWindowClient.bottom - rcWindowClient.top;
  3458.  
  3459.         // Reset the 3D environment
  3460.         IDirect3DDevice9* pd3dDevice = DXUTGetD3DDevice();
  3461.         if( pd3dDevice )
  3462.         {
  3463.             if( FAILED( hr = DXUTReset3DEnvironment() ) )
  3464.             {
  3465.                 if( D3DERR_DEVICELOST == hr )
  3466.                 {
  3467.                     // The device is lost, so wait until it can be reset
  3468.                     GetDXUTState().SetDeviceLost( true );
  3469.                 }
  3470.                 else if( DXUTERR_RESETTINGDEVICEOBJECTS == hr || 
  3471.                          DXUTERR_MEDIANOTFOUND == hr )
  3472.                 {
  3473.                     DXUTDisplayErrorMessage( hr );
  3474.                     DXUTShutdown();
  3475.                     return;
  3476.                 }
  3477.                 else // DXUTERR_RESETTINGDEVICE
  3478.                 {
  3479.                     // Reset failed, but the device wasn't lost so something bad happened, 
  3480.                     // so recreate the device to try to recover
  3481.                     pDeviceSettings = GetDXUTState().GetCurrentDeviceSettings();
  3482.                     if( FAILED( DXUTChangeDevice( pDeviceSettings, NULL, true ) ) )
  3483.                     {
  3484.                         DXUTShutdown();
  3485.                         return;
  3486.                     }
  3487.                 }
  3488.             }
  3489.         }
  3490.  
  3491.         DXUTPause( false, false );
  3492.     }
  3493.  
  3494.     DXUTCheckForWindowMonitorChange();
  3495. }
  3496.  
  3497.  
  3498. //--------------------------------------------------------------------------------------
  3499. // Prepare the window for a possible change between windowed mode and full screen mode
  3500. // by adjusting the window style and its menu.
  3501. //--------------------------------------------------------------------------------------
  3502. void DXUTAdjustWindowStyle( HWND hWnd, bool bWindowed )
  3503. {
  3504.     if( bWindowed )
  3505.     {
  3506.         // If different device windows are used for windowed mode and fullscreen mode,
  3507.         // hide the fullscreen window so that it doesn't obscure the screen.
  3508.         if( GetDXUTState().GetHWNDDeviceFullScreen() != GetDXUTState().GetHWNDDeviceWindowed() )
  3509.         {
  3510.             ::ShowWindow( GetDXUTState().GetHWNDDeviceFullScreen(), SW_HIDE );
  3511.         }
  3512.  
  3513.         // Set windowed-mode style
  3514.         SetWindowLong( hWnd, GWL_STYLE, GetDXUTState().GetWinStyle() );
  3515.         if( GetDXUTState().GetMenu() != NULL )
  3516.         {
  3517.             SetMenu( hWnd, GetDXUTState().GetMenu() );
  3518.         }
  3519.     }
  3520.     else
  3521.     {
  3522.         // If different device windows are used for windowed mode and fullscreen mode,
  3523.         // restore and show the fullscreen device window.
  3524.         if( GetDXUTState().GetHWNDDeviceFullScreen() != GetDXUTState().GetHWNDDeviceWindowed() )
  3525.         {
  3526.             if( ::IsIconic( GetDXUTState().GetHWNDDeviceFullScreen() ) )
  3527.                 ::ShowWindow( GetDXUTState().GetHWNDDeviceFullScreen(), SW_RESTORE );
  3528.             ::ShowWindow( GetDXUTState().GetHWNDDeviceFullScreen(), SW_SHOW );
  3529.         }
  3530.  
  3531.         // Set full screen mode style
  3532.         SetWindowLong( hWnd, GWL_STYLE, WS_POPUP|WS_SYSMENU|WS_VISIBLE );
  3533.         if( GetDXUTState().GetMenu() )
  3534.         {
  3535.             HMENU hMenu = GetMenu( hWnd );
  3536.             GetDXUTState().SetMenu( hMenu );
  3537.             SetMenu( hWnd, NULL );
  3538.         }
  3539.     }
  3540. }
  3541.  
  3542.  
  3543. //--------------------------------------------------------------------------------------
  3544. // Handles app's message loop and rendering when idle.  If DXUTCreateDevice*() or DXUTSetDevice() 
  3545. // has not already been called, it will call DXUTCreateWindow() with the default parameters.  
  3546. //--------------------------------------------------------------------------------------
  3547. HRESULT DXUTMainLoop( HACCEL hAccel )
  3548. {
  3549.     HRESULT hr;
  3550.  
  3551.     // Not allowed to call this from inside the device callbacks or reenter
  3552.     if( GetDXUTState().GetInsideDeviceCallback() || GetDXUTState().GetInsideMainloop() )
  3553.     {
  3554.         if( GetDXUTState().GetExitCode() == 0 )
  3555.             GetDXUTState().SetExitCode(1);
  3556.         return DXUT_ERR_MSGBOX( L"DXUTMainLoop", E_FAIL );
  3557.     }
  3558.  
  3559.     GetDXUTState().SetInsideMainloop( true );
  3560.  
  3561.     // If DXUTCreateDevice*() or DXUTSetDevice() has not already been called, 
  3562.     // then call DXUTCreateDevice() with the default parameters.         
  3563.     if( !GetDXUTState().GetDeviceCreated() ) 
  3564.     {
  3565.         if( GetDXUTState().GetDeviceCreateCalled() )
  3566.         {
  3567.             if( GetDXUTState().GetExitCode() == 0 )
  3568.                 GetDXUTState().SetExitCode(1);
  3569.             return E_FAIL; // DXUTCreateDevice() must first succeed for this function to succeed
  3570.         }
  3571.  
  3572.         hr = DXUTCreateDevice();
  3573.         if( FAILED(hr) )
  3574.         {
  3575.             if( GetDXUTState().GetExitCode() == 0 )
  3576.                 GetDXUTState().SetExitCode(1);
  3577.             return hr;
  3578.         }
  3579.     }
  3580.  
  3581.     HWND hWnd = DXUTGetHWND();
  3582.  
  3583.     // DXUTInit() must have been called and succeeded for this function to proceed
  3584.     // DXUTCreateWindow() or DXUTSetWindow() must have been called and succeeded for this function to proceed
  3585.     // DXUTCreateDevice() or DXUTCreateDeviceFromSettings() or DXUTSetDevice() must have been called and succeeded for this function to proceed
  3586.     if( !GetDXUTState().GetDXUTInited() || !GetDXUTState().GetWindowCreated() || !GetDXUTState().GetDeviceCreated() )
  3587.     {
  3588.         if( GetDXUTState().GetExitCode() == 0 )
  3589.             GetDXUTState().SetExitCode(1);
  3590.         return DXUT_ERR_MSGBOX( L"DXUTMainLoop", E_FAIL );
  3591.     }
  3592.  
  3593.     // Now we're ready to receive and process Windows messages.
  3594.     bool bGotMsg;
  3595.     MSG  msg;
  3596.     msg.message = WM_NULL;
  3597.     PeekMessage( &msg, NULL, 0U, 0U, PM_NOREMOVE );
  3598.  
  3599.     while( WM_QUIT != msg.message  )
  3600.     {
  3601.         // Use PeekMessage() so we can use idle time to render the scene. 
  3602.         bGotMsg = ( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) != 0 );
  3603.  
  3604.         if( bGotMsg )
  3605.         {
  3606.             // Translate and dispatch the message
  3607.             if( hAccel == NULL || hWnd == NULL || 
  3608.                 0 == TranslateAccelerator( hWnd, hAccel, &msg ) )
  3609.             {
  3610.                 TranslateMessage( &msg );
  3611.                 DispatchMessage( &msg );
  3612.             }
  3613.         }
  3614.         else
  3615.         {
  3616.             // Render a frame during idle time (no messages are waiting)
  3617.             DXUTRender3DEnvironment();
  3618.         }
  3619.     }
  3620.  
  3621.     // Cleanup the accelerator table
  3622.     if( hAccel != NULL )
  3623.         DestroyAcceleratorTable( hAccel );
  3624.  
  3625.     GetDXUTState().SetInsideMainloop( false );
  3626.  
  3627.     return S_OK;
  3628. }
  3629.  
  3630.  
  3631. //--------------------------------------------------------------------------------------
  3632. // Render the 3D environment by:
  3633. //      - Checking if the device is lost and trying to reset it if it is
  3634. //      - Get the elapsed time since the last frame
  3635. //      - Calling the app's framemove and render callback
  3636. //      - Calling Present()
  3637. //--------------------------------------------------------------------------------------
  3638. void DXUTRender3DEnvironment()
  3639. {
  3640.     HRESULT hr;
  3641.    
  3642.     IDirect3DDevice9* pd3dDevice = DXUTGetD3DDevice();
  3643.     if( NULL == pd3dDevice )
  3644.         return;
  3645.  
  3646.     if( GetDXUTState().GetDeviceLost() || DXUTIsRenderingPaused() )
  3647.     {
  3648.         // Window is minimized or paused so yield 
  3649.         // CPU time to other processes
  3650.         Sleep( 100 ); 
  3651.     }
  3652.  
  3653.     if( !GetDXUTState().GetActive() )
  3654.     {
  3655.         // Window is not in focus so yield CPU time to other processes
  3656.         Sleep( 20 );
  3657.     }
  3658.  
  3659.     if( GetDXUTState().GetDeviceLost() && !GetDXUTState().GetRenderingPaused() )
  3660.     {
  3661.         // Test the cooperative level to see if it's okay to render
  3662.         if( FAILED( hr = pd3dDevice->TestCooperativeLevel() ) )
  3663.         {
  3664.             if( D3DERR_DEVICELOST == hr )
  3665.             {
  3666.                 // The device has been lost but cannot be reset at this time.  
  3667.                 // So wait until it can be reset.
  3668.                 Sleep( 50 );
  3669.                 return;
  3670.             }
  3671.  
  3672.             // If we are windowed, read the desktop format and 
  3673.             // ensure that the Direct3D device is using the same format 
  3674.             // since the user could have changed the desktop bitdepth 
  3675.             if( DXUTIsWindowed() )
  3676.             {
  3677.                 D3DDISPLAYMODE adapterDesktopDisplayMode;
  3678.                 IDirect3D9* pD3D = DXUTGetD3DObject();
  3679.                 DXUTDeviceSettings* pDeviceSettings = GetDXUTState().GetCurrentDeviceSettings();
  3680.                 pD3D->GetAdapterDisplayMode( pDeviceSettings->AdapterOrdinal, &adapterDesktopDisplayMode );
  3681.                 if( pDeviceSettings->AdapterFormat != adapterDesktopDisplayMode.Format )
  3682.                 {
  3683.                     DXUTMatchOptions matchOptions;
  3684.                     matchOptions.eAdapterOrdinal     = DXUTMT_PRESERVE_INPUT;
  3685.                     matchOptions.eDeviceType         = DXUTMT_PRESERVE_INPUT;
  3686.                     matchOptions.eWindowed           = DXUTMT_PRESERVE_INPUT;
  3687.                     matchOptions.eAdapterFormat      = DXUTMT_PRESERVE_INPUT;
  3688.                     matchOptions.eVertexProcessing   = DXUTMT_CLOSEST_TO_INPUT;
  3689.                     matchOptions.eResolution         = DXUTMT_CLOSEST_TO_INPUT;
  3690.                     matchOptions.eBackBufferFormat   = DXUTMT_CLOSEST_TO_INPUT;
  3691.                     matchOptions.eBackBufferCount    = DXUTMT_CLOSEST_TO_INPUT;
  3692.                     matchOptions.eMultiSample        = DXUTMT_CLOSEST_TO_INPUT;
  3693.                     matchOptions.eSwapEffect         = DXUTMT_CLOSEST_TO_INPUT;
  3694.                     matchOptions.eDepthFormat        = DXUTMT_CLOSEST_TO_INPUT;
  3695.                     matchOptions.eStencilFormat      = DXUTMT_CLOSEST_TO_INPUT;
  3696.                     matchOptions.ePresentFlags       = DXUTMT_CLOSEST_TO_INPUT;
  3697.                     matchOptions.eRefreshRate        = DXUTMT_CLOSEST_TO_INPUT;
  3698.                     matchOptions.ePresentInterval    = DXUTMT_CLOSEST_TO_INPUT;
  3699.  
  3700.                     DXUTDeviceSettings deviceSettings = DXUTGetDeviceSettings();
  3701.                     deviceSettings.AdapterFormat = adapterDesktopDisplayMode.Format;
  3702.  
  3703.                     hr = DXUTFindValidDeviceSettings( &deviceSettings, &deviceSettings, &matchOptions );
  3704.                     if( FAILED(hr) ) // the call will fail if no valid devices were found
  3705.                     {
  3706.                         DXUTDisplayErrorMessage( DXUTERR_NOCOMPATIBLEDEVICES );
  3707.                         DXUTShutdown();
  3708.                     }
  3709.  
  3710.                     // Change to a Direct3D device created from the new device settings.  
  3711.                     // If there is an existing device, then either reset or recreate the scene
  3712.                     hr = DXUTChangeDevice( &deviceSettings, NULL, false );
  3713.                     if( FAILED(hr) )  
  3714.                     {
  3715.                         DXUTShutdown();
  3716.                     }
  3717.  
  3718.                     return;
  3719.                 }
  3720.             }
  3721.  
  3722.             // Try to reset the device
  3723.             if( FAILED( hr = DXUTReset3DEnvironment() ) )
  3724.             {
  3725.                 if( D3DERR_DEVICELOST == hr )
  3726.                 {
  3727.                     // The device was lost again, so continue waiting until it can be reset.
  3728.                     Sleep( 50 );
  3729.                     return;
  3730.                 }
  3731.                 else if( DXUTERR_RESETTINGDEVICEOBJECTS == hr || 
  3732.                          DXUTERR_MEDIANOTFOUND == hr )
  3733.                 {
  3734.                     DXUTDisplayErrorMessage( hr );
  3735.                     DXUTShutdown();
  3736.                     return;
  3737.                 }
  3738.                 else
  3739.                 {
  3740.                     // Reset failed, but the device wasn't lost so something bad happened, 
  3741.                     // so recreate the device to try to recover
  3742.                     DXUTDeviceSettings* pDeviceSettings = GetDXUTState().GetCurrentDeviceSettings();
  3743.                     if( FAILED( DXUTChangeDevice( pDeviceSettings, NULL, true ) ) )
  3744.                     {
  3745.                         DXUTShutdown();
  3746.                         return;
  3747.                     }
  3748.                 }
  3749.             }
  3750.         }
  3751.  
  3752.         GetDXUTState().SetDeviceLost( false );
  3753.     }
  3754.  
  3755.     // Get the app's time, in seconds. Skip rendering if no time elapsed
  3756.     double fTime        = DXUTGetGlobalTimer()->GetTime();
  3757.     float fElapsedTime  = (float) DXUTGetGlobalTimer()->GetElapsedTime();
  3758.  
  3759.     // Store the time for the app
  3760.     if( GetDXUTState().GetConstantFrameTime() )
  3761.     {        
  3762.         fElapsedTime = GetDXUTState().GetTimePerFrame();
  3763.         fTime     = DXUTGetTime() + fElapsedTime;
  3764.     }
  3765.  
  3766.     GetDXUTState().SetTime( fTime );
  3767.     GetDXUTState().SetElapsedTime( fElapsedTime );
  3768.  
  3769.     // Update the FPS stats
  3770.     DXUTUpdateFrameStats();
  3771.  
  3772.     // If the settings dialog exists and is being shown, then 
  3773.     // render it instead of rendering the app's scene
  3774.     CD3DSettingsDlg* pD3DSettingsDlg = GetDXUTState().GetD3DSettingsDlg();
  3775.     if( pD3DSettingsDlg && DXUTGetShowSettingsDialog() )
  3776.     {
  3777.         if( !GetDXUTState().GetRenderingPaused() )
  3778.         {
  3779.             // Clear the render target and the zbuffer 
  3780.             pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET, 0x00003F3F, 1.0f, 0);
  3781.  
  3782.             // Render the scene
  3783.             if( SUCCEEDED( pd3dDevice->BeginScene() ) )
  3784.             {
  3785.                 pD3DSettingsDlg->OnRender( fElapsedTime );
  3786.                 pd3dDevice->EndScene();
  3787.             }
  3788.         }
  3789.     }
  3790.     else
  3791.     {
  3792.         DXUTHandleTimers();
  3793.  
  3794.         // Animate the scene by calling the app's frame move callback
  3795.         LPDXUTCALLBACKFRAMEMOVE pCallbackFrameMove = GetDXUTState().GetFrameMoveFunc();
  3796.         if( pCallbackFrameMove != NULL )
  3797.         {
  3798.             pCallbackFrameMove( pd3dDevice, fTime, fElapsedTime );
  3799.             pd3dDevice = DXUTGetD3DDevice();
  3800.             if( NULL == pd3dDevice )
  3801.                 return;
  3802.         }
  3803.  
  3804.         if( !GetDXUTState().GetRenderingPaused() )
  3805.         {
  3806.             // Render the scene by calling the app's render callback
  3807.             LPDXUTCALLBACKFRAMERENDER pCallbackFrameRender = GetDXUTState().GetFrameRenderFunc();
  3808.             if( pCallbackFrameRender != NULL )
  3809.             {
  3810.                 pCallbackFrameRender( pd3dDevice, fTime, fElapsedTime );
  3811.                 pd3dDevice = DXUTGetD3DDevice();
  3812.                 if( NULL == pd3dDevice )
  3813.                     return;
  3814.             }
  3815.         }
  3816.     }
  3817.  
  3818.     if( !GetDXUTState().GetRenderingPaused() )
  3819.     {
  3820.         // Show the frame on the primary surface.
  3821.         hr = pd3dDevice->Present( NULL, NULL, NULL, NULL );
  3822.         if( FAILED(hr) )
  3823.         {
  3824.             if( D3DERR_DEVICELOST == hr )
  3825.             {
  3826.                 GetDXUTState().SetDeviceLost( true );
  3827.             }
  3828.             else if( D3DERR_DRIVERINTERNALERROR == hr )
  3829.             {
  3830.                 // When D3DERR_DRIVERINTERNALERROR is returned from Present(),
  3831.                 // the application can do one of the following:
  3832.                 // 
  3833.                 // - End, with the pop-up window saying that the application cannot continue 
  3834.                 //   because of problems in the display adapter and that the user should 
  3835.                 //   contact the adapter manufacturer.
  3836.                 //
  3837.                 // - Attempt to restart by calling IDirect3DDevice9::Reset, which is essentially the same 
  3838.                 //   path as recovering from a lost device. If IDirect3DDevice9::Reset fails with 
  3839.                 //   D3DERR_DRIVERINTERNALERROR, the application should end immediately with the message 
  3840.                 //   that the user should contact the adapter manufacturer.
  3841.                 // 
  3842.                 // The framework attempts the path of resetting the device
  3843.                 // 
  3844.                 GetDXUTState().SetDeviceLost( true );
  3845.             }
  3846.         }
  3847.     }
  3848.  
  3849.     // Update current frame #
  3850.     int nFrame = GetDXUTState().GetCurrentFrameNumber();
  3851.     nFrame++;
  3852.     GetDXUTState().SetCurrentFrameNumber( nFrame );
  3853.  
  3854.     // Check to see if the app should shutdown due to cmdline
  3855.     if( GetDXUTState().GetOverrideQuitAfterFrame() != 0 )
  3856.     {
  3857.         if( nFrame > GetDXUTState().GetOverrideQuitAfterFrame() )
  3858.             DXUTShutdown();
  3859.     }
  3860.  
  3861.     return;
  3862. }
  3863.  
  3864.  
  3865. //--------------------------------------------------------------------------------------
  3866. // Updates the string which describes the device 
  3867. //--------------------------------------------------------------------------------------
  3868. void DXUTUpdateDeviceStats( D3DDEVTYPE DeviceType, DWORD BehaviorFlags, D3DADAPTER_IDENTIFIER9* pAdapterIdentifier )
  3869. {
  3870.     // Store device description
  3871.     WCHAR* pstrDeviceStats = GetDXUTState().GetDeviceStats();
  3872.     if( DeviceType == D3DDEVTYPE_REF )
  3873.         wcscpy( pstrDeviceStats, L"REF" );
  3874.     else if( DeviceType == D3DDEVTYPE_HAL )
  3875.         wcscpy( pstrDeviceStats, L"HAL" );
  3876.     else if( DeviceType == D3DDEVTYPE_SW )
  3877.         wcscpy( pstrDeviceStats, L"SW" );
  3878.  
  3879.     if( BehaviorFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING &&
  3880.         BehaviorFlags & D3DCREATE_PUREDEVICE )
  3881.     {
  3882.         if( DeviceType == D3DDEVTYPE_HAL )
  3883.             wcscat( pstrDeviceStats, L" (pure hw vp)" );
  3884.         else
  3885.             wcscat( pstrDeviceStats, L" (simulated pure hw vp)" );
  3886.     }
  3887.     else if( BehaviorFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING )
  3888.     {
  3889.         if( DeviceType == D3DDEVTYPE_HAL )
  3890.             wcscat( pstrDeviceStats, L" (hw vp)" );
  3891.         else
  3892.             wcscat( pstrDeviceStats, L" (simulated hw vp)" );
  3893.     }
  3894.     else if( BehaviorFlags & D3DCREATE_MIXED_VERTEXPROCESSING )
  3895.     {
  3896.         if( DeviceType == D3DDEVTYPE_HAL )
  3897.             wcscat( pstrDeviceStats, L" (mixed vp)" );
  3898.         else
  3899.             wcscat( pstrDeviceStats, L" (simulated mixed vp)" );
  3900.     }
  3901.     else if( BehaviorFlags & D3DCREATE_SOFTWARE_VERTEXPROCESSING )
  3902.     {
  3903.         wcscat( pstrDeviceStats, L" (sw vp)" );
  3904.     }
  3905.  
  3906.     if( DeviceType == D3DDEVTYPE_HAL )
  3907.     {
  3908.         // Be sure not to overflow m_strDeviceStats when appending the adapter 
  3909.         // description, since it can be long.  Note that the adapter description
  3910.         // is initially CHAR and must be converted to WCHAR.
  3911.         wcscat( pstrDeviceStats, L": " );
  3912.  
  3913.         const int cchDesc = sizeof(pAdapterIdentifier->Description);
  3914.         WCHAR szDescription[cchDesc];
  3915.  
  3916.         MultiByteToWideChar( CP_ACP, 0, pAdapterIdentifier->Description, -1, szDescription, cchDesc );
  3917.         szDescription[cchDesc-1] = 0;
  3918.         int maxAppend = 255 - lstrlen(pstrDeviceStats) - 1;
  3919.         wcsncat( pstrDeviceStats, szDescription, maxAppend );
  3920.         pstrDeviceStats[255] = 0;
  3921.     }
  3922. }
  3923.  
  3924.  
  3925. //--------------------------------------------------------------------------------------
  3926. // Updates the frames/sec stat once per second
  3927. //--------------------------------------------------------------------------------------
  3928. void DXUTUpdateFrameStats()
  3929. {
  3930.     // Keep track of the frame count
  3931.     double fLastTime = GetDXUTState().GetLastStatsUpdateTime();
  3932.     DWORD dwFrames  = GetDXUTState().GetLastStatsUpdateFrames();
  3933.     double fTime = DXUTGetGlobalTimer()->GetAbsoluteTime();
  3934.     dwFrames++;
  3935.     GetDXUTState().SetLastStatsUpdateFrames( dwFrames );
  3936.  
  3937.     // Update the scene stats once per second
  3938.     if( fTime - fLastTime > 1.0f )
  3939.     {
  3940.         float fFPS = (float) (dwFrames / (fTime - fLastTime));
  3941.         GetDXUTState().SetFPS( fFPS );
  3942.         GetDXUTState().SetLastStatsUpdateTime( fTime );
  3943.         GetDXUTState().SetLastStatsUpdateFrames( 0 );
  3944.  
  3945.         WCHAR* pstrFrameStats = GetDXUTState().GetFrameStats();
  3946.         WCHAR* pstrStaticFrameStats = GetDXUTState().GetStaticFrameStats();
  3947.         _snwprintf( pstrFrameStats, 256, pstrStaticFrameStats, fFPS );
  3948.         pstrFrameStats[255] = 0;
  3949.     }
  3950. }
  3951.  
  3952.  
  3953. //--------------------------------------------------------------------------------------
  3954. // Updates the static part of the frame stats so it doesn't have be generated every frame
  3955. //--------------------------------------------------------------------------------------
  3956. void DXUTUpdateStaticFrameStats()
  3957. {
  3958.     DXUTDeviceSettings* pDeviceSettings = GetDXUTState().GetCurrentDeviceSettings();
  3959.     if( NULL == pDeviceSettings )
  3960.         return;
  3961.     CD3DEnumeration* pd3dEnum = DXUTPrepareEnumerationObject();
  3962.     if( NULL == pd3dEnum )
  3963.         return;
  3964.  
  3965.     CD3DEnumDeviceSettingsCombo* pDeviceSettingsCombo = pd3dEnum->GetDeviceSettingsCombo( pDeviceSettings->AdapterOrdinal, pDeviceSettings->DeviceType, pDeviceSettings->AdapterFormat, pDeviceSettings->pp.BackBufferFormat, pDeviceSettings->pp.Windowed );
  3966.     if( NULL == pDeviceSettingsCombo )
  3967.         return;
  3968.  
  3969.     WCHAR strFmt[100];
  3970.     D3DPRESENT_PARAMETERS* pPP = &pDeviceSettings->pp;
  3971.  
  3972.     if( pDeviceSettingsCombo->AdapterFormat == pDeviceSettingsCombo->BackBufferFormat )
  3973.     {
  3974.         wcsncpy( strFmt, DXUTD3DFormatToString( pDeviceSettingsCombo->AdapterFormat, false ), 100 );
  3975.     }
  3976.     else
  3977.     {
  3978.         _snwprintf( strFmt, 100, L"backbuf %s, adapter %s", 
  3979.             DXUTD3DFormatToString( pDeviceSettingsCombo->BackBufferFormat, false ), 
  3980.             DXUTD3DFormatToString( pDeviceSettingsCombo->AdapterFormat, false ) );
  3981.     }
  3982.     strFmt[99] = 0;
  3983.  
  3984.     WCHAR strDepthFmt[100];
  3985.     if( pPP->EnableAutoDepthStencil )
  3986.     {
  3987.         _snwprintf( strDepthFmt, 100, L" (%s)", DXUTD3DFormatToString( pPP->AutoDepthStencilFormat, false ) );
  3988.         strDepthFmt[99] = 0;
  3989.     }
  3990.     else
  3991.     {
  3992.         // No depth buffer
  3993.         strDepthFmt[0] = 0;
  3994.     }
  3995.  
  3996.     WCHAR strMultiSample[100];
  3997.     switch( pPP->MultiSampleType )
  3998.     {
  3999.         case D3DMULTISAMPLE_NONMASKABLE: wcsncpy( strMultiSample, L" (Nonmaskable Multisample)", 100 ); break;
  4000.         case D3DMULTISAMPLE_NONE:        wcsncpy( strMultiSample, L"", 100 ); break;
  4001.         default:                         _snwprintf( strMultiSample, 100, L" (%dx Multisample)", pPP->MultiSampleType ); break;
  4002.     }
  4003.     strMultiSample[99] = 0;
  4004.  
  4005.     WCHAR* pstrStaticFrameStats = GetDXUTState().GetStaticFrameStats();
  4006.     _snwprintf( pstrStaticFrameStats, 256, L"%%.02f fps (%dx%d), %s%s%s", 
  4007.                 pPP->BackBufferWidth, pPP->BackBufferHeight,
  4008.                 strFmt, strDepthFmt, strMultiSample );
  4009.     pstrStaticFrameStats[255] = 0;
  4010. }
  4011.  
  4012.  
  4013. //--------------------------------------------------------------------------------------
  4014. // Handles window messages 
  4015. //--------------------------------------------------------------------------------------
  4016. LRESULT CALLBACK DXUTStaticWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
  4017. {
  4018.     // If the settings dialog exists and is being show then pass messages to it 
  4019.     CD3DSettingsDlg* pD3DSettingsDlg = GetDXUTState().GetD3DSettingsDlg();
  4020.     if( pD3DSettingsDlg && DXUTGetShowSettingsDialog() )
  4021.     {
  4022.         pD3DSettingsDlg->HandleMessages( hWnd, uMsg, wParam, lParam );
  4023.     }
  4024.     else
  4025.     {
  4026.         // Consolidate the keyboard messages and pass them to the app's keyboard callback
  4027.         if( uMsg == WM_KEYDOWN ||
  4028.             uMsg == WM_SYSKEYDOWN || 
  4029.             uMsg == WM_KEYUP ||
  4030.             uMsg == WM_SYSKEYUP )
  4031.         {
  4032.             bool bKeyDown = (uMsg == WM_KEYDOWN || uMsg == WM_SYSKEYDOWN);
  4033.             DWORD dwMask = (1 << 29);
  4034.             bool bAltDown = ( (lParam & dwMask) != 0 );
  4035.  
  4036.             bool* bKeys = GetDXUTState().GetKeys();
  4037.             bKeys[ (BYTE) (wParam & 0xFF) ] = bKeyDown;
  4038.  
  4039.             LPDXUTCALLBACKKEYBOARD pCallbackKeyboard = GetDXUTState().GetKeyboardFunc();
  4040.             if( pCallbackKeyboard )
  4041.                 pCallbackKeyboard( (UINT)wParam, bKeyDown, bAltDown );           
  4042.         }
  4043.  
  4044.         // Consolidate the mouse button messages and pass them to the app's mouse callback
  4045.         if( uMsg == WM_LBUTTONDOWN ||
  4046.             uMsg == WM_LBUTTONUP ||
  4047.             uMsg == WM_LBUTTONDBLCLK ||
  4048.             uMsg == WM_MBUTTONDOWN ||
  4049.             uMsg == WM_MBUTTONUP ||
  4050.             uMsg == WM_MBUTTONDBLCLK ||
  4051.             uMsg == WM_RBUTTONDOWN ||
  4052.             uMsg == WM_RBUTTONUP ||
  4053.             uMsg == WM_RBUTTONDBLCLK ||
  4054.             uMsg == WM_XBUTTONDOWN ||
  4055.             uMsg == WM_XBUTTONUP ||
  4056.             uMsg == WM_XBUTTONDBLCLK ||
  4057.             uMsg == WM_MOUSEWHEEL || 
  4058.             (GetDXUTState().GetNotifyOnMouseMove() && uMsg == WM_MOUSEMOVE) )
  4059.         {
  4060.             int xPos = (short)LOWORD(lParam);
  4061.             int yPos = (short)HIWORD(lParam);
  4062.  
  4063.             if( uMsg == WM_MOUSEWHEEL )
  4064.             {
  4065.                 // WM_MOUSEWHEEL passes screen mouse coords
  4066.                 // so convert them to client coords
  4067.                 POINT pt;
  4068.                 pt.x = xPos; pt.y = yPos;
  4069.                 ScreenToClient( hWnd, &pt );
  4070.                 xPos = pt.x; yPos = pt.y;
  4071.             }
  4072.  
  4073.             int nMouseWheelDelta = 0;
  4074.             if( uMsg == WM_MOUSEWHEEL ) 
  4075.                 nMouseWheelDelta = (short) HIWORD(wParam);
  4076.  
  4077.             int nMouseButtonState = LOWORD(wParam);
  4078.             bool bLeftButton  = ((nMouseButtonState & MK_LBUTTON) != 0);
  4079.             bool bRightButton = ((nMouseButtonState & MK_RBUTTON) != 0);
  4080.             bool bMiddleButton = ((nMouseButtonState & MK_MBUTTON) != 0);
  4081.             bool bSideButton1 = ((nMouseButtonState & MK_XBUTTON1) != 0);
  4082.             bool bSideButton2 = ((nMouseButtonState & MK_XBUTTON2) != 0);
  4083.  
  4084.             bool* bMouseButtons = GetDXUTState().GetMouseButtons();
  4085.             bMouseButtons[0] = bLeftButton;
  4086.             bMouseButtons[1] = bMiddleButton;
  4087.             bMouseButtons[2] = bRightButton;
  4088.             bMouseButtons[3] = bSideButton1;
  4089.             bMouseButtons[4] = bSideButton2;
  4090.  
  4091.             LPDXUTCALLBACKMOUSE pCallbackMouse = GetDXUTState().GetMouseFunc();
  4092.             if( pCallbackMouse )
  4093.                 pCallbackMouse( bLeftButton, bRightButton, bMiddleButton, bSideButton1, bSideButton2, nMouseWheelDelta, xPos, yPos );
  4094.         }
  4095.  
  4096.         // Pass all messages to the app's MsgProc callback, and don't 
  4097.         // process further messages if the apps says not to.
  4098.         LPDXUTCALLBACKMSGPROC pCallbackMsgProc = GetDXUTState().GetWindowMsgFunc();
  4099.         if( pCallbackMsgProc )
  4100.         {
  4101.             bool bNoFurtherProcessing = false;
  4102.             LRESULT nResult = pCallbackMsgProc( hWnd, uMsg, wParam, lParam, &bNoFurtherProcessing );
  4103.             if( bNoFurtherProcessing )
  4104.                 return nResult;
  4105.         }
  4106.     }
  4107.  
  4108.     switch( uMsg )
  4109.     {
  4110.         case WM_PAINT:
  4111.         {
  4112.             IDirect3DDevice9* pd3dDevice = DXUTGetD3DDevice();
  4113.  
  4114.             // Handle paint messages when the app is paused
  4115.             if( pd3dDevice && DXUTIsRenderingPaused() && 
  4116.                 GetDXUTState().GetDeviceObjectsCreated() && GetDXUTState().GetDeviceObjectsReset() )
  4117.             {
  4118.                 HRESULT hr;
  4119.                 double fTime = DXUTGetTime();
  4120.                 float fElapsedTime = DXUTGetElapsedTime();
  4121.  
  4122.                 if( pD3DSettingsDlg && DXUTGetShowSettingsDialog() )
  4123.                 {
  4124.                     // Clear the render target and the zbuffer 
  4125.                     pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, 0x00003F3F, 1.0f, 0);
  4126.  
  4127.                     // Render the scene
  4128.                     if( SUCCEEDED( pd3dDevice->BeginScene() ) )
  4129.                     {
  4130.                         pD3DSettingsDlg->OnRender( fElapsedTime );
  4131.                         pd3dDevice->EndScene();
  4132.                     }
  4133.                 }
  4134.                 else
  4135.                 {
  4136.                     LPDXUTCALLBACKFRAMERENDER pCallbackFrameRender = GetDXUTState().GetFrameRenderFunc();
  4137.                     if( pCallbackFrameRender != NULL )
  4138.                         pCallbackFrameRender( pd3dDevice, fTime, fElapsedTime );
  4139.                 }
  4140.  
  4141.                 hr = pd3dDevice->Present( NULL, NULL, NULL, NULL );
  4142.                 if( D3DERR_DEVICELOST == hr )
  4143.                 {
  4144.                     GetDXUTState().SetDeviceLost( true );
  4145.                 }
  4146.                 else if( D3DERR_DRIVERINTERNALERROR == hr )
  4147.                 {
  4148.                     // When D3DERR_DRIVERINTERNALERROR is returned from Present(),
  4149.                     // the application can do one of the following:
  4150.                     // 
  4151.                     // - End, with the pop-up window saying that the application cannot continue 
  4152.                     //   because of problems in the display adapter and that the user should 
  4153.                     //   contact the adapter manufacturer.
  4154.                     //
  4155.                     // - Attempt to restart by calling IDirect3DDevice9::Reset, which is essentially the same 
  4156.                     //   path as recovering from a lost device. If IDirect3DDevice9::Reset fails with 
  4157.                     //   D3DERR_DRIVERINTERNALERROR, the application should end immediately with the message 
  4158.                     //   that the user should contact the adapter manufacturer.
  4159.                     // 
  4160.                     // The framework attempts the path of resetting the device
  4161.                     // 
  4162.                     GetDXUTState().SetDeviceLost( true );
  4163.                 }
  4164.             }
  4165.             break;
  4166.         }
  4167.  
  4168.         case WM_SIZE:
  4169.             // Pick up possible changes to window style due to maximize, etc.
  4170.             if( DXUTIsWindowed() && DXUTGetHWND() != NULL )
  4171.                 GetDXUTState().SetWinStyle( GetWindowLong( DXUTGetHWND(), GWL_STYLE ) );
  4172.  
  4173.             if( SIZE_MINIMIZED == wParam )
  4174.             {
  4175.                 if( GetDXUTState().GetClipCursorWhenFullScreen() && !DXUTIsWindowed() )
  4176.                     ClipCursor( NULL );
  4177.                 DXUTPause( true, true ); // Pause while we're minimized
  4178.                 GetDXUTState().SetMinimized( true );
  4179.                 GetDXUTState().SetMaximized( false );
  4180.             }
  4181.             else if( SIZE_MAXIMIZED == wParam )
  4182.             {
  4183.                 if( GetDXUTState().GetMinimized() )
  4184.                     DXUTPause( false, false ); // Unpause since we're no longer minimized
  4185.                 GetDXUTState().SetMinimized( false );
  4186.                 GetDXUTState().SetMaximized( true );
  4187.                 DXUTHandlePossibleSizeChange();
  4188.             }
  4189.             else if( SIZE_RESTORED == wParam )
  4190.             {
  4191.                 if( GetDXUTState().GetMaximized() )
  4192.                 {
  4193.                     GetDXUTState().SetMaximized( false );
  4194.                     DXUTHandlePossibleSizeChange();
  4195.                 }
  4196.                 else if( GetDXUTState().GetMinimized() )
  4197.                 {
  4198.                     DXUTPause( false, false ); // Unpause since we're no longer minimized
  4199.                     GetDXUTState().SetMinimized( false );
  4200.                     DXUTHandlePossibleSizeChange();
  4201.                 }
  4202.                 else
  4203.                 {
  4204.                     // If we're neither maximized nor minimized, the window size 
  4205.                     // is changing by the user dragging the window edges.  In this 
  4206.                     // case, we don't reset the device yet -- we wait until the 
  4207.                     // user stops dragging, and a WM_EXITSIZEMOVE message comes.
  4208.                 }
  4209.             }
  4210.             break;
  4211.  
  4212.         case WM_GETMINMAXINFO:
  4213.             ((MINMAXINFO*)lParam)->ptMinTrackSize.x = MIN_WINDOW_SIZE_X;
  4214.             ((MINMAXINFO*)lParam)->ptMinTrackSize.y = MIN_WINDOW_SIZE_Y;
  4215.             break;
  4216.  
  4217.         case WM_ENTERSIZEMOVE:
  4218.             // Halt frame movement while the app is sizing or moving
  4219.             DXUTPause( true, true );
  4220.             break;
  4221.  
  4222.         case WM_EXITSIZEMOVE:
  4223.             DXUTPause( false, false );
  4224.             DXUTHandlePossibleSizeChange();
  4225.             break;
  4226.  
  4227.         case WM_SETCURSOR:
  4228.             // Turn off Windows cursor in full screen mode
  4229.             if( !DXUTIsRenderingPaused() && !DXUTIsWindowed() )
  4230.             {
  4231.                 SetCursor( NULL );
  4232.                 IDirect3DDevice9* pd3dDevice = DXUTGetD3DDevice();
  4233.                 if( pd3dDevice && GetDXUTState().GetShowCursorWhenFullScreen() )
  4234.                     pd3dDevice->ShowCursor( true );
  4235.                 return true; // prevent Windows from setting cursor to window class cursor
  4236.             }
  4237.             break;
  4238.  
  4239.          case WM_MOUSEMOVE:
  4240.             if( !DXUTIsRenderingPaused() && !DXUTIsWindowed() )
  4241.             {
  4242.                 IDirect3DDevice9* pd3dDevice = DXUTGetD3DDevice();
  4243.                 if( pd3dDevice )
  4244.                 {
  4245.                     POINT ptCursor;
  4246.                     GetCursorPos( &ptCursor );
  4247.                     pd3dDevice->SetCursorPosition( ptCursor.x, ptCursor.y, 0 );
  4248.                 }
  4249.             }
  4250.             break;
  4251.  
  4252.        case WM_ACTIVATEAPP:
  4253.             if( wParam == TRUE )
  4254.             {
  4255.                 // Upon returning to this app, potentially disable shortcut keys 
  4256.                 // (Windows key, accessibility shortcuts) 
  4257.                 if( DXUTIsWindowed() )
  4258.                     DXUTAllowShortcutKeys( GetDXUTState().GetAllowShortcutKeysWhenWindowed() );
  4259.                 else
  4260.                     DXUTAllowShortcutKeys( GetDXUTState().GetAllowShortcutKeysWhenFullscreen() );
  4261.                 GetDXUTState().SetActive( true );
  4262.             }
  4263.             else 
  4264.             {
  4265.                 if( GetDXUTState().GetClipCursorWhenFullScreen() && !DXUTIsWindowed() )
  4266.                     ClipCursor( NULL );
  4267.  
  4268.                 // Restore shortcut keys (Windows key, accessibility shortcuts) to original state
  4269.                 //
  4270.                 // This is important to call here if the shortcuts are disabled, 
  4271.                 // because if this is not done then the Windows key will continue to 
  4272.                 // be disabled while this app is running which is very bad.
  4273.                 // If the app crashes, the Windows key will return to normal.
  4274.                 DXUTAllowShortcutKeys( true );
  4275.                 GetDXUTState().SetActive( false );
  4276.             }
  4277.             break;
  4278.  
  4279.        case WM_ENTERMENULOOP:
  4280.             // Pause the app when menus are displayed
  4281.             DXUTPause( true, true );
  4282.             break;
  4283.  
  4284.         case WM_EXITMENULOOP:
  4285.             DXUTPause( false, false );
  4286.             break;
  4287.  
  4288.         case WM_NCHITTEST:
  4289.             // Prevent the user from selecting the menu in full screen mode
  4290.             if( !DXUTIsWindowed() )
  4291.                 return HTCLIENT;
  4292.             break;
  4293.  
  4294.         case WM_POWERBROADCAST:
  4295.             switch( wParam )
  4296.             {
  4297.                 #ifndef PBT_APMQUERYSUSPEND
  4298.                     #define PBT_APMQUERYSUSPEND 0x0000
  4299.                 #endif
  4300.                 case PBT_APMQUERYSUSPEND:
  4301.                     // At this point, the app should save any data for open
  4302.                     // network connections, files, etc., and prepare to go into
  4303.                     // a suspended mode.  The app can use the MsgProc callback
  4304.                     // to handle this if desired.
  4305.                     return true;
  4306.  
  4307.                 #ifndef PBT_APMRESUMESUSPEND
  4308.                     #define PBT_APMRESUMESUSPEND 0x0007
  4309.                 #endif
  4310.                 case PBT_APMRESUMESUSPEND:
  4311.                     // At this point, the app should recover any data, network
  4312.                     // connections, files, etc., and resume running from when
  4313.                     // the app was suspended. The app can use the MsgProc callback
  4314.                     // to handle this if desired.
  4315.                     return true;
  4316.             }
  4317.             break;
  4318.  
  4319.         case WM_SYSCOMMAND:
  4320.             // Prevent moving/sizing and power loss in full screen mode
  4321.             switch( wParam )
  4322.             {
  4323.                 case SC_MOVE:
  4324.                 case SC_SIZE:
  4325.                 case SC_MAXIMIZE:
  4326.                 case SC_KEYMENU:
  4327.                 case SC_MONITORPOWER:
  4328.                     if( !DXUTIsWindowed() )
  4329.                         return 1;
  4330.                     break;
  4331.             }
  4332.             break;
  4333.  
  4334.         case WM_SYSCHAR:
  4335.         {
  4336.             if( GetDXUTState().GetHandleDefaultHotkeys() )
  4337.             {
  4338.                 switch( wParam )
  4339.                 {
  4340.                     case VK_RETURN:
  4341.                     {
  4342.                         // Toggle full screen upon alt-enter 
  4343.                         DWORD dwMask = (1 << 29);
  4344.                         if( (lParam & dwMask) != 0 )
  4345.                         {
  4346.                             // Toggle the full screen/window mode
  4347.                             DXUTPause( true, true );
  4348.                             DXUTToggleFullScreen();
  4349.                             DXUTPause( false, false );                        
  4350.                             return 0;
  4351.                         }
  4352.                     }
  4353.                 }
  4354.             }
  4355.             break;
  4356.         }
  4357.  
  4358.         case WM_KEYDOWN:
  4359.         {
  4360.             if( GetDXUTState().GetHandleDefaultHotkeys() )
  4361.             {
  4362.                 switch( wParam )
  4363.                 {
  4364.                     case VK_F2:
  4365.                     {
  4366.                         DXUTSetShowSettingsDialog( !DXUTGetShowSettingsDialog() );
  4367.                         break;
  4368.                     }
  4369.  
  4370.                     case VK_F3:
  4371.                     {
  4372.                         DXUTPause( true, true );
  4373.                         DXUTToggleREF();
  4374.                         DXUTPause( false, false );                        
  4375.                         break;
  4376.                     }
  4377.  
  4378.                     case VK_F8:
  4379.                     {
  4380.                         bool bWireFrame = GetDXUTState().GetWireframeMode();
  4381.                         bWireFrame = !bWireFrame; 
  4382.                         GetDXUTState().SetWireframeMode( bWireFrame );
  4383.  
  4384.                         IDirect3DDevice9* pd3dDevice = DXUTGetD3DDevice();
  4385.                         if( pd3dDevice )
  4386.                             pd3dDevice->SetRenderState( D3DRS_FILLMODE, (bWireFrame) ? D3DFILL_WIREFRAME : D3DFILL_SOLID ); 
  4387.                         break;
  4388.                     }
  4389.  
  4390.                     case VK_ESCAPE:
  4391.                     {
  4392.                         // Received key to exit app
  4393.                         SendMessage( hWnd, WM_CLOSE, 0, 0 );
  4394.                     }
  4395.  
  4396.                     case VK_PAUSE: 
  4397.                     {
  4398.                         bool bTimePaused = DXUTIsTimePaused();
  4399.                         bTimePaused = !bTimePaused;
  4400.                         if( bTimePaused ) 
  4401.                             DXUTPause( true, false ); 
  4402.                         else
  4403.                             DXUTPause( false, false ); 
  4404.                         break; 
  4405.                     }
  4406.                 }
  4407.             }
  4408.             break;
  4409.         }
  4410.  
  4411.         case WM_CLOSE:
  4412.         {
  4413.             HMENU hMenu;
  4414.             hMenu = GetMenu(hWnd);
  4415.             if( hMenu != NULL )
  4416.                 DestroyMenu( hMenu );
  4417.             DestroyWindow( hWnd );
  4418.             UnregisterClass( L"Direct3DWindowClass", NULL );
  4419.             GetDXUTState().SetHWNDFocus( NULL );
  4420.             GetDXUTState().SetHWNDDeviceFullScreen( NULL );
  4421.             GetDXUTState().SetHWNDDeviceWindowed( NULL );
  4422.             return 0;
  4423.         }
  4424.  
  4425.         case WM_DESTROY:
  4426.             PostQuitMessage(0);
  4427.             break;
  4428.  
  4429.         default:
  4430.             // At this point the message is still not handled.  We let the
  4431.             // CDXUTIMEEditBox's static message proc handle the msg.
  4432.             // This is because some IME messages must be handled to ensure
  4433.             // proper functionalities and the static msg proc ensures that
  4434.             // this happens even if no control has the input focus.
  4435.             if( CDXUTIMEEditBox::StaticMsgProc( uMsg, wParam, lParam ) )
  4436.                 return 0;
  4437.     }
  4438.  
  4439.     // Don't allow the F10 key to act as a shortcut to the menu bar
  4440.     // by not passing these messages to the DefWindowProc only when
  4441.     // there's no menu present
  4442.     if( GetDXUTState().GetMenu() == NULL && (uMsg == WM_SYSKEYDOWN || uMsg == WM_SYSKEYUP) && wParam == VK_F10 )
  4443.         return 0;
  4444.     else
  4445.         return DefWindowProc( hWnd, uMsg, wParam, lParam );
  4446. }
  4447.  
  4448.  
  4449. //--------------------------------------------------------------------------------------
  4450. // Resets the state associated with the sample framework
  4451. //--------------------------------------------------------------------------------------
  4452. void DXUTResetFrameworkState()
  4453. {
  4454.     GetDXUTState().Destroy();
  4455.     GetDXUTState().Create();
  4456. }
  4457.  
  4458.  
  4459. //--------------------------------------------------------------------------------------
  4460. // Closes down the window.  When the window closes, it will cleanup everything
  4461. //--------------------------------------------------------------------------------------
  4462. void DXUTShutdown()
  4463. {
  4464.     HWND hWnd = DXUTGetHWND();
  4465.     if( hWnd != NULL )
  4466.         SendMessage( hWnd, WM_CLOSE, 0, 0 );
  4467.  
  4468.     DXUTCleanup3DEnvironment( true );
  4469.  
  4470.     // Restore shortcut keys (Windows key, accessibility shortcuts) to original state
  4471.     // This is important to call here if the shortcuts are disabled, 
  4472.     // because accessibility setting changes are permanent.
  4473.     // This means that if this is not done then the accessibility settings 
  4474.     // might not be the same as when the app was started. 
  4475.     // If the app crashes without restoring the settings, this is also true so it
  4476.     // would be wise to backup/restore the settings from a file so they can be 
  4477.     // restored when the crashed app is run again.
  4478.     DXUTAllowShortcutKeys( true );
  4479.     
  4480.     GetDXUTState().SetD3DEnumeration( NULL );
  4481.  
  4482.     IDirect3D9* pD3D = DXUTGetD3DObject();
  4483.     SAFE_RELEASE( pD3D );
  4484.     GetDXUTState().SetD3D( NULL );
  4485. }
  4486.  
  4487.  
  4488. //--------------------------------------------------------------------------------------
  4489. // Cleans up the 3D environment by:
  4490. //      - Calls the device lost callback 
  4491. //      - Calls the device destroyed callback 
  4492. //      - Releases the D3D device
  4493. //--------------------------------------------------------------------------------------
  4494. void DXUTCleanup3DEnvironment( bool bReleaseSettings )
  4495. {
  4496.     DXUTGetGlobalDialogResourceManager()->OnLostDevice();
  4497.     DXUTGetGlobalDialogResourceManager()->OnDestroyDevice();
  4498.  
  4499.     DXUTGetGlobalResourceCache().OnLostDevice();
  4500.     DXUTGetGlobalResourceCache().OnDestroyDevice();
  4501.  
  4502.     IDirect3DDevice9* pd3dDevice = DXUTGetD3DDevice();
  4503.     if( pd3dDevice != NULL )
  4504.     {
  4505.         // If the settings dialog exists, then call its OnLostDevice() and OnDestroyedDevice()
  4506.         CD3DSettingsDlg* pD3DSettingsDlg = GetDXUTState().GetD3DSettingsDlg();
  4507.         if( pD3DSettingsDlg )
  4508.         {
  4509.             pD3DSettingsDlg->OnLostDevice();
  4510.             pD3DSettingsDlg->OnDestroyDevice();
  4511.         }
  4512.  
  4513.         GetDXUTState().SetInsideDeviceCallback( true );
  4514.  
  4515.         DXUTGetGlobalDialogResourceManager()->OnLostDevice();
  4516.         DXUTGetGlobalResourceCache().OnLostDevice();
  4517.         
  4518.         // Call the app's device lost callback
  4519.         LPDXUTCALLBACKDEVICELOST pCallbackDeviceLost = GetDXUTState().GetDeviceLostFunc();
  4520.         if( pCallbackDeviceLost != NULL )
  4521.             pCallbackDeviceLost();
  4522.         GetDXUTState().SetDeviceObjectsReset( false );
  4523.  
  4524.         // Call the app's device destroyed callback
  4525.         LPDXUTCALLBACKDEVICEDESTROYED pCallbackDeviceDestroyed = GetDXUTState().GetDeviceDestroyedFunc();
  4526.         if( pCallbackDeviceDestroyed != NULL )
  4527.             pCallbackDeviceDestroyed();
  4528.         GetDXUTState().SetDeviceObjectsCreated( false );
  4529.  
  4530.         GetDXUTState().SetInsideDeviceCallback( false );
  4531.  
  4532.         // Release the D3D device and in debug configs, displays a message box if there 
  4533.         // are unrelease objects.
  4534.         if( pd3dDevice )
  4535.         {
  4536.             if( pd3dDevice->Release() > 0 )  
  4537.             {
  4538.                 DXUTDisplayErrorMessage( DXUTERR_NONZEROREFCOUNT );
  4539.                 DXUT_ERR( L"DXUTCleanup3DEnvironment", DXUTERR_NONZEROREFCOUNT );
  4540.             }
  4541.         }
  4542.         GetDXUTState().SetD3DDevice( NULL );
  4543.  
  4544.         if( bReleaseSettings )
  4545.         {
  4546.             DXUTDeviceSettings* pOldDeviceSettings = GetDXUTState().GetCurrentDeviceSettings();
  4547.             SAFE_DELETE(pOldDeviceSettings);  
  4548.             GetDXUTState().SetCurrentDeviceSettings( NULL );
  4549.         }
  4550.  
  4551.         D3DSURFACE_DESC* pbackBufferSurfaceDesc = GetDXUTState().GetBackBufferSurfaceDesc();
  4552.         ZeroMemory( pbackBufferSurfaceDesc, sizeof(D3DSURFACE_DESC) );
  4553.  
  4554.         D3DCAPS9* pd3dCaps = GetDXUTState().GetCaps();
  4555.         ZeroMemory( pd3dCaps, sizeof(D3DCAPS9) );
  4556.  
  4557.         GetDXUTState().SetDeviceCreated( false );
  4558.     }
  4559. }
  4560.  
  4561.  
  4562. //--------------------------------------------------------------------------------------
  4563. // Starts a user defined timer callback
  4564. //--------------------------------------------------------------------------------------
  4565. HRESULT DXUTSetTimer( LPDXUTCALLBACKTIMER pCallbackTimer, float fTimeoutInSecs, UINT* pnIDEvent ) 
  4566.     if( pCallbackTimer == NULL )
  4567.         return DXUT_ERR_MSGBOX( L"DXUTSetTimer", E_INVALIDARG ); 
  4568.  
  4569.     HRESULT hr;
  4570.     DXUT_TIMER DXUTTimer;
  4571.     DXUTTimer.pCallbackTimer = pCallbackTimer;
  4572.     DXUTTimer.fTimeoutInSecs = fTimeoutInSecs;
  4573.     DXUTTimer.fCountdown = fTimeoutInSecs;
  4574.     DXUTTimer.bEnabled = true;
  4575.  
  4576.     CGrowableArray<DXUT_TIMER>* pTimerList = GetDXUTState().GetTimerList();
  4577.     if( pTimerList == NULL )
  4578.     {
  4579.         pTimerList = new CGrowableArray<DXUT_TIMER>;
  4580.         if( pTimerList == NULL )
  4581.             return E_OUTOFMEMORY; 
  4582.         GetDXUTState().SetTimerList( pTimerList );
  4583.     }
  4584.  
  4585.     if( FAILED( hr = pTimerList->Add( DXUTTimer ) ) )
  4586.         return hr;
  4587.  
  4588.     if( pnIDEvent )
  4589.         *pnIDEvent = pTimerList->GetSize();
  4590.  
  4591.     return S_OK; 
  4592. }
  4593.  
  4594.  
  4595. //--------------------------------------------------------------------------------------
  4596. // Stops a user defined timer callback
  4597. //--------------------------------------------------------------------------------------
  4598. HRESULT DXUTKillTimer( UINT nIDEvent ) 
  4599.     CGrowableArray<DXUT_TIMER>* pTimerList = GetDXUTState().GetTimerList();
  4600.     if( pTimerList == NULL )
  4601.         return S_FALSE;
  4602.  
  4603.     if( nIDEvent < (UINT)pTimerList->GetSize() )
  4604.     {
  4605.         DXUT_TIMER DXUTTimer = pTimerList->GetAt(nIDEvent);
  4606.         DXUTTimer.bEnabled = false;
  4607.         pTimerList->SetAt(nIDEvent, DXUTTimer);
  4608.     }
  4609.     else
  4610.     {
  4611.         return DXUT_ERR_MSGBOX( L"DXUTKillTimer", E_INVALIDARG );
  4612.     }
  4613.  
  4614.     return S_OK; 
  4615. }
  4616.  
  4617.  
  4618. //--------------------------------------------------------------------------------------
  4619. // Internal helper function to handle calling the user defined timer callbacks
  4620. //--------------------------------------------------------------------------------------
  4621. void DXUTHandleTimers()
  4622. {
  4623.     float fElapsedTime = DXUTGetElapsedTime();
  4624.  
  4625.     CGrowableArray<DXUT_TIMER>* pTimerList = GetDXUTState().GetTimerList();
  4626.     if( pTimerList == NULL )
  4627.         return;
  4628.  
  4629.     // Walk through the list of timer callbacks
  4630.     for( int i=0; i<pTimerList->GetSize(); i++ )
  4631.     {
  4632.         DXUT_TIMER DXUTTimer = pTimerList->GetAt(i);
  4633.         if( DXUTTimer.bEnabled )
  4634.         {
  4635.             DXUTTimer.fCountdown -= fElapsedTime;
  4636.  
  4637.             // Call the callback if count down expired
  4638.             if( DXUTTimer.fCountdown < 0 )
  4639.             {
  4640.                 DXUTTimer.pCallbackTimer( i );
  4641.                 DXUTTimer.fCountdown = DXUTTimer.fTimeoutInSecs;
  4642.             }
  4643.             pTimerList->SetAt(i, DXUTTimer);
  4644.         }
  4645.     }
  4646. }
  4647.  
  4648.  
  4649. //--------------------------------------------------------------------------------------
  4650. // Show the settings dialog, and create if needed
  4651. //--------------------------------------------------------------------------------------
  4652. void DXUTSetShowSettingsDialog( bool bShow )
  4653. {
  4654.     GetDXUTState().SetShowD3DSettingsDlg( bShow );
  4655.  
  4656.     if( bShow )
  4657.     {
  4658.         CD3DSettingsDlg* pD3DSettingsDlg = DXUTPrepareSettingsDialog();
  4659.         pD3DSettingsDlg->Refresh();
  4660.     }
  4661. }
  4662.  
  4663.  
  4664. //--------------------------------------------------------------------------------------
  4665. // External state access functions
  4666. //--------------------------------------------------------------------------------------
  4667. IDirect3D9* DXUTGetD3DObject()                      { return GetDXUTState().GetD3D(); }        
  4668. IDirect3DDevice9* DXUTGetD3DDevice()                { return GetDXUTState().GetD3DDevice(); }  
  4669. const D3DSURFACE_DESC* DXUTGetBackBufferSurfaceDesc() { return GetDXUTState().GetBackBufferSurfaceDesc(); }
  4670. const D3DCAPS9* DXUTGetDeviceCaps()                 { return GetDXUTState().GetCaps(); }
  4671. HWND DXUTGetHWND()                                  { return DXUTIsWindowed() ? GetDXUTState().GetHWNDDeviceWindowed() : GetDXUTState().GetHWNDDeviceFullScreen(); }
  4672. HWND DXUTGetHWNDFocus()                             { return GetDXUTState().GetHWNDFocus(); }
  4673. HWND DXUTGetHWNDDeviceFullScreen()                  { return GetDXUTState().GetHWNDDeviceFullScreen(); }
  4674. HWND DXUTGetHWNDDeviceWindowed()                    { return GetDXUTState().GetHWNDDeviceWindowed(); }
  4675. const RECT &DXUTGetWindowClientRect()               { return GetDXUTState().GetWindowClientRect(); }
  4676. double DXUTGetTime()                                { return GetDXUTState().GetTime(); }
  4677. float DXUTGetElapsedTime()                          { return GetDXUTState().GetElapsedTime(); }
  4678. float DXUTGetFPS()                                  { return GetDXUTState().GetFPS(); }
  4679. LPCWSTR DXUTGetWindowTitle()                        { return GetDXUTState().GetWindowTitle(); }
  4680. LPCWSTR DXUTGetFrameStats()                         { return GetDXUTState().GetFrameStats(); }
  4681. LPCWSTR DXUTGetDeviceStats()                        { return GetDXUTState().GetDeviceStats(); }
  4682. bool DXUTGetShowSettingsDialog()                    { return GetDXUTState().GetShowD3DSettingsDlg(); }
  4683. bool DXUTIsRenderingPaused()                        { return GetDXUTState().GetPauseRenderingCount() > 0; }
  4684. bool DXUTIsTimePaused()                             { return GetDXUTState().GetPauseTimeCount() > 0; }
  4685. int DXUTGetExitCode()                               { return GetDXUTState().GetExitCode(); }
  4686.  
  4687. bool DXUTIsKeyDown( BYTE vKey )                     
  4688.     bool* bKeys = GetDXUTState().GetKeys(); 
  4689.     if( vKey >= 0xA0 && vKey <= 0xA5 )  // VK_LSHIFT, VK_RSHIFT, VK_LCONTROL, VK_RCONTROL, VK_LMENU, VK_RMENU
  4690.         return GetAsyncKeyState( vKey ) != 0; // these keys only are tracked via GetAsyncKeyState()
  4691.     else if( vKey >= 0x01 && vKey <= 0x06 && vKey != 0x03 ) // mouse buttons (VK_*BUTTON)
  4692.         return DXUTIsMouseButtonDown(vKey);
  4693.     else
  4694.         return bKeys[vKey];
  4695. }
  4696. bool DXUTIsMouseButtonDown( BYTE vButton )          
  4697.     bool* bMouseButtons = GetDXUTState().GetMouseButtons(); 
  4698.     int nIndex = DXUTMapButtonToArrayIndex(vButton); 
  4699.     return bMouseButtons[nIndex]; 
  4700. }
  4701. void DXUTSetMultimonSettings( bool bAutoChangeAdapter )
  4702. {
  4703.     GetDXUTState().SetAutoChangeAdapter( bAutoChangeAdapter );
  4704. }
  4705. void DXUTSetCursorSettings( bool bShowCursorWhenFullScreen, bool bClipCursorWhenFullScreen ) 
  4706.     GetDXUTState().SetClipCursorWhenFullScreen(bClipCursorWhenFullScreen); 
  4707.     GetDXUTState().SetShowCursorWhenFullScreen(bShowCursorWhenFullScreen); 
  4708. }
  4709. void DXUTSetConstantFrameTime( bool bEnabled, float fTimePerFrame ) 
  4710.     if( GetDXUTState().GetOverrideConstantFrameTime() ) 
  4711.     { 
  4712.         bEnabled = GetDXUTState().GetOverrideConstantFrameTime(); 
  4713.         fTimePerFrame = GetDXUTState().GetOverrideConstantTimePerFrame(); 
  4714.     } 
  4715.     GetDXUTState().SetConstantFrameTime(bEnabled); 
  4716.     GetDXUTState().SetTimePerFrame(fTimePerFrame); 
  4717. }
  4718.  
  4719.  
  4720. //--------------------------------------------------------------------------------------
  4721. // Return if windowed in the current device.  If no device exists yet, then returns false
  4722. //--------------------------------------------------------------------------------------
  4723. bool DXUTIsWindowed()                               
  4724.     DXUTDeviceSettings* pDeviceSettings = GetDXUTState().GetCurrentDeviceSettings(); 
  4725.     if(pDeviceSettings) 
  4726.         return (pDeviceSettings->pp.Windowed != 0); 
  4727.     else 
  4728.         return false; 
  4729. }
  4730.  
  4731.  
  4732. //--------------------------------------------------------------------------------------
  4733. // Return the present params of the current device.  If no device exists yet, then
  4734. // return blank present params
  4735. //--------------------------------------------------------------------------------------
  4736. D3DPRESENT_PARAMETERS DXUTGetPresentParameters()    
  4737.     DXUTDeviceSettings* pDS = GetDXUTState().GetCurrentDeviceSettings(); 
  4738.     if( pDS ) 
  4739.     {
  4740.         return pDS->pp; 
  4741.     }
  4742.     else 
  4743.     {
  4744.         D3DPRESENT_PARAMETERS pp;
  4745.         ZeroMemory( &pp, sizeof(D3DPRESENT_PARAMETERS) );
  4746.         return pp; 
  4747.     }
  4748. }
  4749.  
  4750.  
  4751. //--------------------------------------------------------------------------------------
  4752. // Return the device settings of the current device.  If no device exists yet, then
  4753. // return blank device settings 
  4754. //--------------------------------------------------------------------------------------
  4755. DXUTDeviceSettings DXUTGetDeviceSettings()   
  4756.     DXUTDeviceSettings* pDS = GetDXUTState().GetCurrentDeviceSettings();
  4757.     if( pDS )
  4758.     {
  4759.         return *pDS;
  4760.     }
  4761.     else
  4762.     {
  4763.         DXUTDeviceSettings ds;
  4764.         ZeroMemory( &ds, sizeof(DXUTDeviceSettings) );
  4765.         return ds;
  4766.     }
  4767.  
  4768.  
  4769. //--------------------------------------------------------------------------------------
  4770. // Display an custom error msg box 
  4771. //--------------------------------------------------------------------------------------
  4772. void DXUTDisplayErrorMessage( HRESULT hr )
  4773. {
  4774.     WCHAR strBuffer[512];
  4775.  
  4776.     int nExitCode;
  4777.     bool bFound = true; 
  4778.     switch( hr )
  4779.     {
  4780.         case DXUTERR_NODIRECT3D:             nExitCode = 2; wcsncpy( strBuffer, L"Could not initialize Direct3D. You may want to check that the latest version of DirectX is correctly installed on your system.  Also make sure that this program was compiled with header files that match the installed DirectX DLLs.", 512 ); break;
  4781.         case DXUTERR_INCORRECTVERSION:       nExitCode = 10; wcsncpy( strBuffer, L"Incorrect version of Direct3D and/or D3DX.", 512 ); break;
  4782.         case DXUTERR_MEDIANOTFOUND:          nExitCode = 4; wcsncpy( strBuffer, L"Could not find required media. Ensure that the DirectX SDK is correctly installed.", 512 ); break;
  4783.         case DXUTERR_NONZEROREFCOUNT:        nExitCode = 5; wcsncpy( strBuffer, L"The D3D device has a non-zero reference count, meaning some objects were not released.", 512 ); break;
  4784.         case DXUTERR_CREATINGDEVICE:         nExitCode = 6; wcsncpy( strBuffer, L"Failed creating the Direct3D device.", 512 ); break;
  4785.         case DXUTERR_RESETTINGDEVICE:        nExitCode = 7; wcsncpy( strBuffer, L"Failed resetting the Direct3D device.", 512 ); break;
  4786.         case DXUTERR_CREATINGDEVICEOBJECTS:  nExitCode = 8; wcsncpy( strBuffer, L"Failed creating Direct3D device objects.", 512 ); break;
  4787.         case DXUTERR_RESETTINGDEVICEOBJECTS: nExitCode = 9; wcsncpy( strBuffer, L"Failed resetting Direct3D device objects.", 512 ); break;
  4788.         case DXUTERR_SWITCHEDTOREF:          nExitCode = 0; wcsncpy( strBuffer, L"Switching to the reference rasterizer,\na software device that implements the entire\nDirect3D feature set, but runs very slowly.", 512 ); break;
  4789.         case DXUTERR_NOCOMPATIBLEDEVICES:    
  4790.             nExitCode = 3; 
  4791.             if( GetSystemMetrics(SM_REMOTESESSION) != 0 )
  4792.                 wcsncpy( strBuffer, L"Direct3D does not work over a remote session.", 512 ); 
  4793.             else
  4794.                 wcsncpy( strBuffer, L"Could not find any compatible Direct3D devices.", 512 ); 
  4795.             break;
  4796.         default: bFound = false; nExitCode = 1;break;
  4797.     }   
  4798.     strBuffer[511] = 0;
  4799.  
  4800.     GetDXUTState().SetExitCode(nExitCode);
  4801.  
  4802.     bool bShowMsgBoxOnError = GetDXUTState().GetShowMsgBoxOnError();
  4803.     if( bFound && bShowMsgBoxOnError )
  4804.     {
  4805.         if( DXUTGetWindowTitle()[0] == 0 )
  4806.             MessageBox( DXUTGetHWND(), strBuffer, L"DirectX Application", MB_ICONERROR|MB_OK );
  4807.         else
  4808.             MessageBox( DXUTGetHWND(), strBuffer, DXUTGetWindowTitle(), MB_ICONERROR|MB_OK );
  4809.     }
  4810. }
  4811.  
  4812.  
  4813. //--------------------------------------------------------------------------------------
  4814. // Display error msg box to help debug 
  4815. //--------------------------------------------------------------------------------------
  4816. HRESULT WINAPI DXUTTrace( const CHAR* strFile, DWORD dwLine, HRESULT hr,
  4817.                           const WCHAR* strMsg, bool bPopMsgBox )
  4818. {
  4819.     bool bShowMsgBoxOnError = GetDXUTState().GetShowMsgBoxOnError();
  4820.     if( bPopMsgBox && bShowMsgBoxOnError == false )
  4821.         bPopMsgBox = false;
  4822.  
  4823.     return DXTrace( strFile, dwLine, hr, strMsg, bPopMsgBox );
  4824. }
  4825.  
  4826.  
  4827. //--------------------------------------------------------------------------------------
  4828. // Checks to see if the HWND changed monitors, and if it did it creates a device 
  4829. // from the monitor's adapter and recreates the scene.
  4830. //--------------------------------------------------------------------------------------
  4831. void DXUTCheckForWindowMonitorChange()
  4832. {
  4833.     // Don't do this if the user doesn't want it
  4834.     if( GetDXUTState().GetAutoChangeAdapter() == false )
  4835.         return;
  4836.  
  4837.     HRESULT hr;
  4838.     HMONITOR hWindowMonitor = MonitorFromWindow( DXUTGetHWND(), MONITOR_DEFAULTTOPRIMARY );
  4839.     HMONITOR hAdapterMonitor = GetDXUTState().GetAdapterMonitor();
  4840.     if( hWindowMonitor != hAdapterMonitor )
  4841.     {
  4842.         DXUTPause( true, true );
  4843.  
  4844.         UINT newOrdinal;
  4845.         if( SUCCEEDED( DXUTGetAdapterOrdinalFromMonitor( hWindowMonitor, &newOrdinal ) ) )
  4846.         {
  4847.             // Find the closest valid device settings with the new ordinal
  4848.             DXUTDeviceSettings deviceSettings = DXUTGetDeviceSettings();
  4849.             deviceSettings.AdapterOrdinal = newOrdinal;
  4850.             
  4851.             DXUTMatchOptions matchOptions;
  4852.             matchOptions.eAdapterOrdinal     = DXUTMT_PRESERVE_INPUT;
  4853.             matchOptions.eDeviceType         = DXUTMT_CLOSEST_TO_INPUT;
  4854.             matchOptions.eWindowed           = DXUTMT_CLOSEST_TO_INPUT;
  4855.             matchOptions.eAdapterFormat      = DXUTMT_CLOSEST_TO_INPUT;
  4856.             matchOptions.eVertexProcessing   = DXUTMT_CLOSEST_TO_INPUT;
  4857.             matchOptions.eResolution         = DXUTMT_CLOSEST_TO_INPUT;
  4858.             matchOptions.eBackBufferFormat   = DXUTMT_CLOSEST_TO_INPUT;
  4859.             matchOptions.eBackBufferCount    = DXUTMT_CLOSEST_TO_INPUT;
  4860.             matchOptions.eMultiSample        = DXUTMT_CLOSEST_TO_INPUT;
  4861.             matchOptions.eSwapEffect         = DXUTMT_CLOSEST_TO_INPUT;
  4862.             matchOptions.eDepthFormat        = DXUTMT_CLOSEST_TO_INPUT;
  4863.             matchOptions.eStencilFormat      = DXUTMT_CLOSEST_TO_INPUT;
  4864.             matchOptions.ePresentFlags       = DXUTMT_CLOSEST_TO_INPUT;
  4865.             matchOptions.eRefreshRate        = DXUTMT_CLOSEST_TO_INPUT;
  4866.             matchOptions.ePresentInterval    = DXUTMT_CLOSEST_TO_INPUT;
  4867.  
  4868.             hr = DXUTFindValidDeviceSettings( &deviceSettings, &deviceSettings, &matchOptions );
  4869.             if( SUCCEEDED(hr) ) 
  4870.             {
  4871.                 // Create a Direct3D device using the new device settings.  
  4872.                 // If there is an existing device, then it will either reset or recreate the scene.
  4873.                 hr = DXUTChangeDevice( &deviceSettings, NULL, false );
  4874.                 if( FAILED(hr) )
  4875.                 {
  4876.                     DXUTShutdown();
  4877.                     DXUTPause( false, false );
  4878.                     return;
  4879.                 }
  4880.             }
  4881.         }
  4882.  
  4883.         DXUTPause( false, false );
  4884.     }    
  4885. }
  4886.  
  4887.  
  4888. //--------------------------------------------------------------------------------------
  4889. // Look for an adapter ordinal that is tied to a HMONITOR
  4890. //--------------------------------------------------------------------------------------
  4891. HRESULT DXUTGetAdapterOrdinalFromMonitor( HMONITOR hMonitor, UINT* pAdapterOrdinal )
  4892. {
  4893.     *pAdapterOrdinal = 0;
  4894.  
  4895.     CD3DEnumeration* pd3dEnum = DXUTPrepareEnumerationObject();
  4896.     IDirect3D9*      pD3D     = DXUTGetD3DObject();
  4897.  
  4898.     CGrowableArray<CD3DEnumAdapterInfo*>* pAdapterList = pd3dEnum->GetAdapterInfoList();
  4899.     for( int iAdapter=0; iAdapter<pAdapterList->GetSize(); iAdapter++ )
  4900.     {
  4901.         CD3DEnumAdapterInfo* pAdapterInfo = pAdapterList->GetAt(iAdapter);
  4902.         HMONITOR hAdapterMonitor = pD3D->GetAdapterMonitor( pAdapterInfo->AdapterOrdinal );
  4903.         if( hAdapterMonitor == hMonitor )
  4904.         {
  4905.             *pAdapterOrdinal = pAdapterInfo->AdapterOrdinal;
  4906.             return S_OK;
  4907.         }
  4908.     }
  4909.  
  4910.     return E_FAIL;
  4911. }
  4912.  
  4913.  
  4914. //--------------------------------------------------------------------------------------
  4915. // Internal function to map MK_* to an array index
  4916. //--------------------------------------------------------------------------------------
  4917. int DXUTMapButtonToArrayIndex( BYTE vButton )
  4918. {
  4919.     switch( vButton )
  4920.     {
  4921.         case MK_LBUTTON: return 0;
  4922.         case VK_MBUTTON: 
  4923.         case MK_MBUTTON: return 1;
  4924.         case MK_RBUTTON: return 2;
  4925.         case VK_XBUTTON1:
  4926.         case MK_XBUTTON1: return 3;
  4927.         case VK_XBUTTON2:
  4928.         case MK_XBUTTON2: return 4;
  4929.     }
  4930.  
  4931.     return 0;
  4932. }